Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/libraries/network/synchronisable/SynchronisableVariable.h @ 8186

Last change on this file since 8186 was 7266, checked in by rgrieder, 14 years ago

Moved Loki library files to separate loki folder in externals.
Also added TypeManip.h (now used in Convert.h) and static_check.h.

  • 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 <loki/TypeTraits.h>
38
39#include "Serialise.h"
40#include "core/GameMode.h"
41#include "network/synchronisable/NetworkCallbackManager.h"
42
43namespace orxonox{
44
45  namespace VariableDirection{
46    enum Value{
47      ToClient=0x1,
48      ToServer=0x2
49    };
50  }
51  namespace Bidirectionality{
52    enum Value{
53      ServerMaster=0x1,
54      ClientMaster=0x2
55    };
56  }
57
58  class _NetworkExport SynchronisableVariableBase
59  {
60    public:
61      virtual uint32_t getData(uint8_t*& mem, uint8_t mode)=0;
62      virtual void putData(uint8_t*& mem, uint8_t mode, bool forceCallback = false)=0;
63      virtual uint32_t getSize(uint8_t mode)=0;
64      virtual void* getReference()=0;
65      virtual uint8_t getMode()=0;
66      virtual ~SynchronisableVariableBase() {}
67    protected:
68      static uint8_t state_;
69  };
70
71  template <class T>
72  class SynchronisableVariable: public SynchronisableVariableBase
73  {
74    public:
75      SynchronisableVariable(T& variable, uint8_t syncDirection=VariableDirection::ToClient, NetworkCallbackBase *cb=0);
76      virtual ~SynchronisableVariable();
77
78      virtual inline uint8_t getMode(){ return mode_; }
79      virtual inline uint32_t getData(uint8_t*& mem, uint8_t mode);
80      virtual inline void putData(uint8_t*& mem, uint8_t mode, bool forceCallback = false);
81      virtual inline uint32_t getSize(uint8_t mode);
82      virtual inline void* getReference(){ return static_cast<void*>(const_cast<typename Loki::TypeTraits<T>::UnqualifiedType*>(&this->variable_)); }
83    protected:
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_)
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_ )
144    {
145      callback = forceCallback || !checkEquality( this->variable_, mem );
146    }
147  // now do a callback if neccessary
148    if ( callback )
149    {
150      NetworkCallbackManager::triggerCallback( this->callback_ );
151    }
152  // write the data
153    loadAndIncrease( this->variable_, mem );
154  }
155
156  template <class T> inline uint32_t SynchronisableVariable<T>::getSize(uint8_t mode)
157  {
158    if ( mode == this->mode_ )
159      return returnSize( this->variable_ );
160    else
161      return 0;
162  }
163
164
165
166
167// ================= Bidirectional Part ================
168
169    template <class T> SynchronisableVariableBidirectional<T>::SynchronisableVariableBidirectional(T& variable, uint8_t master, NetworkCallbackBase *cb):
170    SynchronisableVariable<T>( variable, master, cb ), varBuffer_( variable ), varReference_( 0 )
171    {
172    }
173
174    template <class T> SynchronisableVariableBidirectional<T>::~SynchronisableVariableBidirectional()
175    {
176    }
177
178    template <class T> uint32_t SynchronisableVariableBidirectional<T>::getData(uint8_t*& mem, uint8_t mode)
179    {
180      if ( this->mode_ == mode )
181      {   // we are master for this variable and have to check whether to change the varReference
182        if( this->varBuffer_ != this->variable_ )
183        {
184          this->varReference_++;
185          memcpy(static_cast<void*>(const_cast<typename Loki::TypeTraits<T>::UnqualifiedType*>(&this->varBuffer_)), &this->variable_, sizeof(this->variable_));
186        }
187      }
188  // write the reference number to the stream
189      *static_cast<uint8_t*>(mem) = varReference_;
190      mem += sizeof(this->varReference_);
191  // now write the content
192      saveAndIncrease( this->variable_, mem );
193      return SynchronisableVariableBidirectional::getSize(mode);
194    }
195
196    template <class T> void SynchronisableVariableBidirectional<T>::putData(uint8_t*& mem, uint8_t mode, bool forceCallback)
197    {
198      bool callback = false;
199      if ( this->mode_ == mode )
200      {   //        MASTER
201        // check that the client (source of the data) has a recent version of this variable
202        if ( *static_cast<uint8_t*>(mem) != this->varReference_ )
203        { // wrong reference number, so discard the data
204//           COUT(0) << "discharding data" << endl;
205          mem += getSize( mode ); // SynchronisableVariableBidirectional::getSize returns size of variable + reference
206          return;
207        }
208        else{
209          // apply data
210          if ( checkEquality( this->variable_, mem+sizeof(varReference_) )==true )
211          {
212            mem += getSize( mode );
213            return;
214          }
215          else
216          {
217            mem += sizeof(varReference_);
218            memcpy(static_cast<void*>(const_cast<typename Loki::TypeTraits<T>::UnqualifiedType*>(&this->varBuffer_)), &this->variable_, sizeof(T));
219            if ( this->callback_ )
220              callback = true;
221          }
222        }
223      }
224      else
225      {   // we are slave for this variable
226        if (*static_cast<uint8_t*>(mem) == this->varReference_ && !forceCallback)
227        {
228          mem += getSize( mode ); //just skip the variable because nothing changed
229          return;
230        }
231        else
232        {
233          this->varReference_ = *static_cast<uint8_t*>(mem);
234          mem += sizeof(varReference_);
235          if ( checkEquality( this->variable_, mem ) == false )
236          {
237            // value changed so remark for callback
238            if ( this->callback_ )
239              callback = true;
240          }
241        }
242      }
243  // now do a callback if neccessary
244      if ( callback )
245      {
246        NetworkCallbackManager::triggerCallback( this->callback_ );
247      }
248  // now write the data
249      loadAndIncrease(this->variable_, mem);
250    }
251
252    template <class T> inline uint32_t SynchronisableVariableBidirectional<T>::getSize(uint8_t mode)
253    {
254      return returnSize( this->variable_ ) + sizeof(varReference_);
255    }
256
257
258}
259
260
261#endif /* _SynchronisableVariable_H__ */
Note: See TracBrowser for help on using the repository browser.