Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 10222 was 8858, checked in by landauf, 13 years ago

merged output branch back to trunk.

Changes:

  • you have to include util/Output.h instead of util/Debug.h
  • COUT(x) is now called orxout(level)
  • output levels are now defined by an enum instead of numbers. see util/Output.h for the definition
  • it's possible to use output contexts with orxout(level, context). see util/Output.h for some common contexts. you can define more contexts
  • you must use 'endl' at the end of an output message, '\n' does not flush the message

Output levels:

  • instead of COUT(0) use orxout()
  • instead of COUT(1) use orxout(user_error) or orxout(internal_error)
  • instead of COUT(2) use orxout(user_warning) or orxout(internal_warning)
  • instead of COUT(3) use orxout(user_status/user_info) or orxout(internal_status/internal_info)
  • instead of COUT(4) use orxout(verbose)
  • instead of COUT(5) use orxout(verbose_more)
  • instead of COUT(6) use orxout(verbose_ultra)

Guidelines:

  • user_* levels are for the user, visible in the console and the log-file
  • internal_* levels are for developers, visible in the log-file
  • verbose_* levels are for debugging, only visible if the context of the output is activated

Usage in C++:

  • orxout() << "message" << endl;
  • orxout(level) << "message" << endl;
  • orxout(level, context) << "message" << endl;

Usage in Lua:

  • orxout("message")
  • orxout(orxonox.level.levelname, "message")
  • orxout(orxonox.level.levelname, "context", "message")

Usage in Tcl (and in the in-game-console):

  • orxout levelname message
  • orxout_context levelname context message
  • shortcuts: log message, error message, warning message, status message, info message, debug message
  • Property svn:eol-style set to native
File size: 8.5 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    protected:
68      static uint8_t state_;
69  };
70
71  template <class T>
[2307]72  class SynchronisableVariable: public SynchronisableVariableBase
[2245]73  {
74    public:
[3280]75      SynchronisableVariable(T& variable, uint8_t syncDirection=VariableDirection::ToClient, NetworkCallbackBase *cb=0);
[2245]76      virtual ~SynchronisableVariable();
77
78      virtual inline uint8_t getMode(){ return mode_; }
[3084]79      virtual inline uint32_t getData(uint8_t*& mem, uint8_t mode);
[2307]80      virtual inline void putData(uint8_t*& mem, uint8_t mode, bool forceCallback = false);
[2575]81      virtual inline uint32_t getSize(uint8_t mode);
[3332]82      virtual inline void* getReference(){ return static_cast<void*>(const_cast<typename Loki::TypeTraits<T>::UnqualifiedType*>(&this->variable_)); }
[2245]83    protected:
[6417]84      T&                       variable_;
85      uint8_t                  mode_;
86      NetworkCallbackBase      *callback_;
[2245]87  };
[6417]88
[2245]89  template <class T>
[2307]90  class SynchronisableVariableBidirectional: public SynchronisableVariable<T>
[2245]91  {
92    public:
[3280]93      SynchronisableVariableBidirectional(T& variable, uint8_t master=Bidirectionality::ServerMaster, NetworkCallbackBase *cb=0);
[2245]94      virtual ~SynchronisableVariableBidirectional();
[6417]95
[2245]96      virtual inline uint8_t getMode(){ return 0x3; } //this basically is a hack ^^
[3084]97      virtual inline uint32_t getData(uint8_t*& mem, uint8_t mode);
[2245]98      virtual void putData(uint8_t*& mem, uint8_t mode, bool forceCallback = false);
[3084]99      virtual inline uint32_t getSize(uint8_t mode);
[2245]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  {
[3084]110    if ( state_ == 0x0 )
111    {
112      state_ = GameMode::isMaster() ? 0x1 : 0x2;  // set the appropriate mode here
113    }
[2245]114  }
[6417]115
[2245]116  template <class T> SynchronisableVariable<T>::~SynchronisableVariable()
117  {
[6417]118    if (this->callback_)
[3304]119    {
[2309]120      NetworkCallbackManager::deleteCallback(this->callback_); //safe call for deletion
[3304]121      // this is neccessary because for example for a Vector3 all 3 components of the vector use the same callback
122    }
[2245]123  }
124
[3084]125  template <class T> inline uint32_t SynchronisableVariable<T>::getData(uint8_t*& mem, uint8_t mode)
[2245]126  {
[3102]127    if ( mode == this->mode_ )
[3084]128    {
129      saveAndIncrease( this->variable_, mem );
130      return returnSize( this->variable_ );
131    }
132    else
133      return 0;
[2245]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
[6417]143    if ( this->callback_ )
[2245]144    {
[6417]145      callback = forceCallback || !checkEquality( this->variable_, mem );
[2245]146    }
147  // now do a callback if neccessary
148    if ( callback )
[6417]149    {
[2309]150      NetworkCallbackManager::triggerCallback( this->callback_ );
[6417]151    }
152  // write the data
153    loadAndIncrease( this->variable_, mem );
[2245]154  }
155
[3084]156  template <class T> inline uint32_t SynchronisableVariable<T>::getSize(uint8_t mode)
[2245]157  {
158    if ( mode == this->mode_ )
[3084]159      return returnSize( this->variable_ );
[2245]160    else
161      return 0;
162  }
163
164
[2307]165
166
[2245]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
[3084]178    template <class T> uint32_t SynchronisableVariableBidirectional<T>::getData(uint8_t*& mem, uint8_t mode)
[2245]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_++;
[3332]185          memcpy(static_cast<void*>(const_cast<typename Loki::TypeTraits<T>::UnqualifiedType*>(&this->varBuffer_)), &this->variable_, sizeof(this->variable_));
[2245]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
[3084]192      saveAndIncrease( this->variable_, mem );
193      return SynchronisableVariableBidirectional::getSize(mode);
[2245]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
[8858]204//           orxout(debug_output, context::network) << "discharding data" << endl;
[2245]205          mem += getSize( mode ); // SynchronisableVariableBidirectional::getSize returns size of variable + reference
206          return;
207        }
208        else{
209          // apply data
[3084]210          if ( checkEquality( this->variable_, mem+sizeof(varReference_) )==true )
[2245]211          {
[3084]212            mem += getSize( mode );
[2245]213            return;
214          }
215          else
216          {
[3084]217            mem += sizeof(varReference_);
[3332]218            memcpy(static_cast<void*>(const_cast<typename Loki::TypeTraits<T>::UnqualifiedType*>(&this->varBuffer_)), &this->variable_, sizeof(T));
[6417]219            if ( this->callback_ )
[2245]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_);
[3084]235          if ( checkEquality( this->variable_, mem ) == false )
[2245]236          {
237            // value changed so remark for callback
[6417]238            if ( this->callback_ )
[2245]239              callback = true;
240          }
241        }
242      }
243  // now do a callback if neccessary
244      if ( callback )
[6417]245      {
[2309]246        NetworkCallbackManager::triggerCallback( this->callback_ );
[6417]247      }
248  // now write the data
249      loadAndIncrease(this->variable_, mem);
[2245]250    }
251
[3084]252    template <class T> inline uint32_t SynchronisableVariableBidirectional<T>::getSize(uint8_t mode)
[2245]253    {
[3084]254      return returnSize( this->variable_ ) + sizeof(varReference_);
[2245]255    }
256
[6417]257
[2245]258}
259
260
[3214]261#endif /* _SynchronisableVariable_H__ */
Note: See TracBrowser for help on using the repository browser.