Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 10652 was 10624, checked in by landauf, 9 years ago

merged branch core7 back to trunk

  • Property svn:eol-style set to native
File size: 8.3 KB
RevLine 
[2245]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:
[3084]23 *      Oliver Scheuss
[2245]24 *   Co-authors:
25 *      ...
26 *
27 */
28
29
[3214]30#ifndef _SynchronisableVariable_H__
31#define _SynchronisableVariable_H__
[2245]32
[2307]33#include "network/NetworkPrereqs.h"
34
35#include <cassert>
[3214]36#include <cstring>
[7266]37#include <loki/TypeTraits.h>
38
[6417]39#include "Serialise.h"
[3084]40#include "core/GameMode.h"
[2309]41#include "network/synchronisable/NetworkCallbackManager.h"
[2245]42
43namespace orxonox{
[6417]44
[3280]45  namespace VariableDirection{
46    enum Value{
47      ToClient=0x1,
48      ToServer=0x2
[2245]49    };
[3280]50  }
51  namespace Bidirectionality{
52    enum Value{
53      ServerMaster=0x1,
54      ClientMaster=0x2
[2245]55    };
56  }
[6417]57
[2245]58  class _NetworkExport SynchronisableVariableBase
59  {
60    public:
[3084]61      virtual uint32_t getData(uint8_t*& mem, uint8_t mode)=0;
[2245]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  };
68
69  template <class T>
[2307]70  class SynchronisableVariable: public SynchronisableVariableBase
[2245]71  {
72    public:
[3280]73      SynchronisableVariable(T& variable, uint8_t syncDirection=VariableDirection::ToClient, NetworkCallbackBase *cb=0);
[2245]74      virtual ~SynchronisableVariable();
75
76      virtual inline uint8_t getMode(){ return mode_; }
[3084]77      virtual inline uint32_t getData(uint8_t*& mem, uint8_t mode);
[2307]78      virtual inline void putData(uint8_t*& mem, uint8_t mode, bool forceCallback = false);
[2575]79      virtual inline uint32_t getSize(uint8_t mode);
[3332]80      virtual inline void* getReference(){ return static_cast<void*>(const_cast<typename Loki::TypeTraits<T>::UnqualifiedType*>(&this->variable_)); }
[2245]81    protected:
[6417]82      T&                       variable_;
83      uint8_t                  mode_;
84      NetworkCallbackBase      *callback_;
[2245]85  };
[6417]86
[2245]87  template <class T>
[2307]88  class SynchronisableVariableBidirectional: public SynchronisableVariable<T>
[2245]89  {
90    public:
[3280]91      SynchronisableVariableBidirectional(T& variable, uint8_t master=Bidirectionality::ServerMaster, NetworkCallbackBase *cb=0);
[2245]92      virtual ~SynchronisableVariableBidirectional();
[6417]93
[2245]94      virtual inline uint8_t getMode(){ return 0x3; } //this basically is a hack ^^
[3084]95      virtual inline uint32_t getData(uint8_t*& mem, uint8_t mode);
[2245]96      virtual void putData(uint8_t*& mem, uint8_t mode, bool forceCallback = false);
[3084]97      virtual inline uint32_t getSize(uint8_t mode);
[2245]98    private:
99      T varBuffer_;
100      uint8_t varReference_;
101  };
102
103  // ================= Unidirectional Part ===============
104
105  template <class T> SynchronisableVariable<T>::SynchronisableVariable(T& variable, uint8_t syncDirection, NetworkCallbackBase *cb):
106      variable_( variable ), mode_( syncDirection ), callback_( cb )
107  {
108  }
[6417]109
[2245]110  template <class T> SynchronisableVariable<T>::~SynchronisableVariable()
111  {
[6417]112    if (this->callback_)
[3304]113    {
[2309]114      NetworkCallbackManager::deleteCallback(this->callback_); //safe call for deletion
[3304]115      // this is neccessary because for example for a Vector3 all 3 components of the vector use the same callback
116    }
[2245]117  }
118
[3084]119  template <class T> inline uint32_t SynchronisableVariable<T>::getData(uint8_t*& mem, uint8_t mode)
[2245]120  {
[3102]121    if ( mode == this->mode_ )
[3084]122    {
123      saveAndIncrease( this->variable_, mem );
124      return returnSize( this->variable_ );
125    }
126    else
127      return 0;
[2245]128  }
129
130  template <class T> void SynchronisableVariable<T>::putData(uint8_t*& mem, uint8_t mode, bool forceCallback)
131  {
132    assert ( mode == 0x1 || mode == 0x2 );
133    bool callback = false;
134    if ( mode == this->mode_ ) //don't do anything
135      return;
136  // check whether we need to consider a callback
[6417]137    if ( this->callback_ )
[2245]138    {
[6417]139      callback = forceCallback || !checkEquality( this->variable_, mem );
[2245]140    }
141  // now do a callback if neccessary
142    if ( callback )
[6417]143    {
[2309]144      NetworkCallbackManager::triggerCallback( this->callback_ );
[6417]145    }
146  // write the data
147    loadAndIncrease( this->variable_, mem );
[2245]148  }
149
[3084]150  template <class T> inline uint32_t SynchronisableVariable<T>::getSize(uint8_t mode)
[2245]151  {
152    if ( mode == this->mode_ )
[3084]153      return returnSize( this->variable_ );
[2245]154    else
155      return 0;
156  }
157
158
[2307]159
160
[2245]161// ================= Bidirectional Part ================
162
163    template <class T> SynchronisableVariableBidirectional<T>::SynchronisableVariableBidirectional(T& variable, uint8_t master, NetworkCallbackBase *cb):
164    SynchronisableVariable<T>( variable, master, cb ), varBuffer_( variable ), varReference_( 0 )
165    {
166    }
167
168    template <class T> SynchronisableVariableBidirectional<T>::~SynchronisableVariableBidirectional()
169    {
170    }
171
[3084]172    template <class T> uint32_t SynchronisableVariableBidirectional<T>::getData(uint8_t*& mem, uint8_t mode)
[2245]173    {
174      if ( this->mode_ == mode )
175      {   // we are master for this variable and have to check whether to change the varReference
176        if( this->varBuffer_ != this->variable_ )
177        {
178          this->varReference_++;
[3332]179          memcpy(static_cast<void*>(const_cast<typename Loki::TypeTraits<T>::UnqualifiedType*>(&this->varBuffer_)), &this->variable_, sizeof(this->variable_));
[2245]180        }
181      }
182  // write the reference number to the stream
183      *static_cast<uint8_t*>(mem) = varReference_;
184      mem += sizeof(this->varReference_);
185  // now write the content
[3084]186      saveAndIncrease( this->variable_, mem );
187      return SynchronisableVariableBidirectional::getSize(mode);
[2245]188    }
189
190    template <class T> void SynchronisableVariableBidirectional<T>::putData(uint8_t*& mem, uint8_t mode, bool forceCallback)
191    {
192      bool callback = false;
193      if ( this->mode_ == mode )
194      {   //        MASTER
195        // check that the client (source of the data) has a recent version of this variable
196        if ( *static_cast<uint8_t*>(mem) != this->varReference_ )
197        { // wrong reference number, so discard the data
[8858]198//           orxout(debug_output, context::network) << "discharding data" << endl;
[2245]199          mem += getSize( mode ); // SynchronisableVariableBidirectional::getSize returns size of variable + reference
200          return;
201        }
202        else{
203          // apply data
[3084]204          if ( checkEquality( this->variable_, mem+sizeof(varReference_) )==true )
[2245]205          {
[3084]206            mem += getSize( mode );
[2245]207            return;
208          }
209          else
210          {
[3084]211            mem += sizeof(varReference_);
[3332]212            memcpy(static_cast<void*>(const_cast<typename Loki::TypeTraits<T>::UnqualifiedType*>(&this->varBuffer_)), &this->variable_, sizeof(T));
[6417]213            if ( this->callback_ )
[2245]214              callback = true;
215          }
216        }
217      }
218      else
219      {   // we are slave for this variable
220        if (*static_cast<uint8_t*>(mem) == this->varReference_ && !forceCallback)
221        {
222          mem += getSize( mode ); //just skip the variable because nothing changed
223          return;
224        }
225        else
226        {
227          this->varReference_ = *static_cast<uint8_t*>(mem);
228          mem += sizeof(varReference_);
[3084]229          if ( checkEquality( this->variable_, mem ) == false )
[2245]230          {
231            // value changed so remark for callback
[6417]232            if ( this->callback_ )
[2245]233              callback = true;
234          }
235        }
236      }
237  // now do a callback if neccessary
238      if ( callback )
[6417]239      {
[2309]240        NetworkCallbackManager::triggerCallback( this->callback_ );
[6417]241      }
242  // now write the data
243      loadAndIncrease(this->variable_, mem);
[2245]244    }
245
[3084]246    template <class T> inline uint32_t SynchronisableVariableBidirectional<T>::getSize(uint8_t mode)
[2245]247    {
[3084]248      return returnSize( this->variable_ ) + sizeof(varReference_);
[2245]249    }
250
[6417]251
[2245]252}
253
254
[3214]255#endif /* _SynchronisableVariable_H__ */
Note: See TracBrowser for help on using the repository browser.