Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/presentation2/src/libraries/network/synchronisable/SynchronisableVariable.h @ 6123

Last change on this file since 6123 was 6123, checked in by scheusso, 14 years ago

synchronisation of pointers to classes that inherit from Synchronisable are now possible
just use the normal registerVariable syntax

  • Property svn:eol-style set to native
File size: 8.4 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Oliver Scheuss
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29
30#ifndef _SynchronisableVariable_H__
31#define _SynchronisableVariable_H__
32
33#include "network/NetworkPrereqs.h"
34
35#include <cassert>
36#include <cstring>
37#include "Serialise.h"
38#include "util/TypeTraits.h"
39#include "core/GameMode.h"
40#include "network/synchronisable/NetworkCallbackManager.h"
41
42namespace orxonox{
43 
44  namespace VariableDirection{
45    enum Value{
46      ToClient=0x1,
47      ToServer=0x2
48    };
49  }
50  namespace Bidirectionality{
51    enum Value{
52      ServerMaster=0x1,
53      ClientMaster=0x2
54    };
55  }
56 
57  class _NetworkExport SynchronisableVariableBase
58  {
59    public:
60      virtual uint32_t getData(uint8_t*& mem, uint8_t mode)=0;
61      virtual void putData(uint8_t*& mem, uint8_t mode, bool forceCallback = false)=0;
62      virtual uint32_t getSize(uint8_t mode)=0;
63      virtual void* getReference()=0;
64      virtual uint8_t getMode()=0;
65      virtual ~SynchronisableVariableBase() {}
66    protected:
67      static uint8_t state_;
68  };
69
70  template <class T>
71  class SynchronisableVariable: public SynchronisableVariableBase
72  {
73    public:
74      SynchronisableVariable(T& variable, uint8_t syncDirection=VariableDirection::ToClient, NetworkCallbackBase *cb=0);
75      virtual ~SynchronisableVariable();
76
77      virtual inline uint8_t getMode(){ return mode_; }
78      virtual inline uint32_t getData(uint8_t*& mem, uint8_t mode);
79      virtual inline void putData(uint8_t*& mem, uint8_t mode, bool forceCallback = false);
80      virtual inline uint32_t getSize(uint8_t mode);
81      virtual inline void* getReference(){ return static_cast<void*>(const_cast<typename Loki::TypeTraits<T>::UnqualifiedType*>(&this->variable_)); }
82    protected:
83     
84      T& variable_;
85      uint8_t mode_;
86      NetworkCallbackBase *callback_;
87  };
88 
89  template <class T>
90  class SynchronisableVariableBidirectional: public SynchronisableVariable<T>
91  {
92    public:
93      SynchronisableVariableBidirectional(T& variable, uint8_t master=Bidirectionality::ServerMaster, NetworkCallbackBase *cb=0);
94      virtual ~SynchronisableVariableBidirectional();
95     
96      virtual inline uint8_t getMode(){ return 0x3; } //this basically is a hack ^^
97      virtual inline uint32_t getData(uint8_t*& mem, uint8_t mode);
98      virtual void putData(uint8_t*& mem, uint8_t mode, bool forceCallback = false);
99      virtual inline uint32_t getSize(uint8_t mode);
100    private:
101      T varBuffer_;
102      uint8_t varReference_;
103  };
104
105  // ================= Unidirectional Part ===============
106
107  template <class T> SynchronisableVariable<T>::SynchronisableVariable(T& variable, uint8_t syncDirection, NetworkCallbackBase *cb):
108      variable_( variable ), mode_( syncDirection ), callback_( cb )
109  {
110    if ( state_ == 0x0 )
111    {
112      state_ = GameMode::isMaster() ? 0x1 : 0x2;  // set the appropriate mode here
113    }
114  }
115 
116  template <class T> SynchronisableVariable<T>::~SynchronisableVariable()
117  {
118    if (this->callback_ != 0)
119    {
120      NetworkCallbackManager::deleteCallback(this->callback_); //safe call for deletion
121      // this is neccessary because for example for a Vector3 all 3 components of the vector use the same callback
122    }
123  }
124
125  template <class T> inline uint32_t SynchronisableVariable<T>::getData(uint8_t*& mem, uint8_t mode)
126  {
127    if ( mode == this->mode_ )
128    {
129      saveAndIncrease( this->variable_, mem );
130      return returnSize( this->variable_ );
131    }
132    else
133      return 0;
134  }
135
136  template <class T> void SynchronisableVariable<T>::putData(uint8_t*& mem, uint8_t mode, bool forceCallback)
137  {
138    assert ( mode == 0x1 || mode == 0x2 );
139    bool callback = false;
140    if ( mode == this->mode_ ) //don't do anything
141      return;
142  // check whether we need to consider a callback
143    if ( this->callback_ != 0 )
144    {
145      callback = forceCallback || !checkEquality( this->variable_, mem );
146    }
147  // write the data
148    loadAndIncrease( this->variable_, mem );
149  // now do a callback if neccessary
150    if ( callback )
151      NetworkCallbackManager::triggerCallback( this->callback_ );
152  }
153
154  template <class T> inline uint32_t SynchronisableVariable<T>::getSize(uint8_t mode)
155  {
156    if ( mode == this->mode_ )
157      return returnSize( this->variable_ );
158    else
159      return 0;
160  }
161
162
163
164
165// ================= Bidirectional Part ================
166
167    template <class T> SynchronisableVariableBidirectional<T>::SynchronisableVariableBidirectional(T& variable, uint8_t master, NetworkCallbackBase *cb):
168    SynchronisableVariable<T>( variable, master, cb ), varBuffer_( variable ), varReference_( 0 )
169    {
170    }
171
172    template <class T> SynchronisableVariableBidirectional<T>::~SynchronisableVariableBidirectional()
173    {
174    }
175
176    template <class T> uint32_t SynchronisableVariableBidirectional<T>::getData(uint8_t*& mem, uint8_t mode)
177    {
178      if ( this->mode_ == mode )
179      {   // we are master for this variable and have to check whether to change the varReference
180        if( this->varBuffer_ != this->variable_ )
181        {
182          this->varReference_++;
183          memcpy(static_cast<void*>(const_cast<typename Loki::TypeTraits<T>::UnqualifiedType*>(&this->varBuffer_)), &this->variable_, sizeof(this->variable_));
184        }
185      }
186  // write the reference number to the stream
187      *static_cast<uint8_t*>(mem) = varReference_;
188      mem += sizeof(this->varReference_);
189  // now write the content
190      saveAndIncrease( this->variable_, mem );
191      return SynchronisableVariableBidirectional::getSize(mode);
192    }
193
194    template <class T> void SynchronisableVariableBidirectional<T>::putData(uint8_t*& mem, uint8_t mode, bool forceCallback)
195    {
196      bool callback = false;
197      if ( this->mode_ == mode )
198      {   //        MASTER
199        // check that the client (source of the data) has a recent version of this variable
200        if ( *static_cast<uint8_t*>(mem) != this->varReference_ )
201        { // wrong reference number, so discard the data
202//           COUT(0) << "discharding data" << endl;
203          mem += getSize( mode ); // SynchronisableVariableBidirectional::getSize returns size of variable + reference
204          return;
205        }
206        else{
207          // apply data
208          if ( checkEquality( this->variable_, mem+sizeof(varReference_) )==true )
209          {
210            mem += getSize( mode );
211            return;
212          }
213          else
214          {
215            mem += sizeof(varReference_);
216            memcpy(static_cast<void*>(const_cast<typename Loki::TypeTraits<T>::UnqualifiedType*>(&this->varBuffer_)), &this->variable_, sizeof(T));
217            if ( this->callback_ != 0 )
218              callback = true;
219          }
220        }
221      }
222      else
223      {   // we are slave for this variable
224        if (*static_cast<uint8_t*>(mem) == this->varReference_ && !forceCallback)
225        {
226          mem += getSize( mode ); //just skip the variable because nothing changed
227          return;
228        }
229        else
230        {
231          this->varReference_ = *static_cast<uint8_t*>(mem);
232          mem += sizeof(varReference_);
233          if ( checkEquality( this->variable_, mem ) == false )
234          {
235            // value changed so remark for callback
236            if ( this->callback_ != 0 )
237              callback = true;
238          }
239        }
240      }
241  // now write the data
242      loadAndIncrease(this->variable_, mem);
243  // now do a callback if neccessary
244      if ( callback )
245        NetworkCallbackManager::triggerCallback( this->callback_ );
246    }
247
248    template <class T> inline uint32_t SynchronisableVariableBidirectional<T>::getSize(uint8_t mode)
249    {
250      return returnSize( this->variable_ ) + sizeof(varReference_);
251    }
252 
253
254}
255
256
257#endif /* _SynchronisableVariable_H__ */
Note: See TracBrowser for help on using the repository browser.