Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

reverted r6130

  • 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.