Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/cpp11_v2/src/libraries/network/synchronisable/Synchronisable.h @ 11008

Last change on this file since 11008 was 11002, checked in by landauf, 10 years ago

MultiType now supports strongly typed enum classes. Their values are cast to the underlying type.
MultiType now also uses additional static_asserts to ensure that it is only used with supported values.

  • Property svn:eol-style set to native
File size: 10.1 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, (C) 2007
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29#ifndef _Synchronisable_H__
30#define _Synchronisable_H__
31
32#include "network/NetworkPrereqs.h"
33
34#include <cassert>
35#include <cstring>
36#include <vector>
37#include <map>
38#include <queue>
39#include <set>
40#include <type_traits>
41
42#include "util/mbool.h"
43#include "util/Output.h"
44#include "core/class/OrxonoxInterface.h"
45#include "SynchronisableVariable.h"
46#include "NetworkCallback.h"
47
48
49namespace orxonox
50{
51
52  namespace ObjectDirection{
53    enum Value{
54      None=0x0,
55      ToClient=0x1,
56      ToServer=0x2,
57      Bidirectional=0x3
58    };
59  }
60
61  namespace Priority{
62    enum Value{
63      VeryHigh    = -100,
64      High        = -15,
65      Normal      = 0,
66      Low         = 15,
67      VeryLow     = 100
68    };
69  }
70
71    /**
72   * @brief: stores information about a Synchronisable (light version)
73   *
74   * This class stores the information about a Synchronisable (objectID_, dataSize)
75   * in an emulated bitset.
76   * Bit 1 to 31 store the size of the Data the synchronisable consumes in the stream
77   * Bit 32 is a bool and defines whether the variables are stored in diff mode
78   * Byte 5 to 8: objectID_
79   */
80  class _NetworkExport SynchronisableHeaderLight
81  {
82    protected:
83      uint8_t* data_;
84    public:
85      SynchronisableHeaderLight(uint8_t* data)
86        { data_ = data; }
87      inline static uint32_t getSize()
88        { return 6; }
89      inline uint16_t getDataSize() const
90        { return (*(uint16_t*)data_) & 0x7FFF; } //only use the first 31 bits
91      inline void setDataSize(uint16_t size)
92        { *(uint16_t*)(data_) = (size & 0x7FFFFFFF) | (*(uint16_t*)(data_) & 0x8000 ); }
93      inline bool isDiffed() const
94        { return ( (*(uint16_t*)data_) & 0x8000 ) == 0x8000; }
95      inline void setDiffed( bool b)
96        { *(uint16_t*)(data_) = (b << 15) | (*(uint16_t*)(data_) & 0x7FFF ); }
97      inline uint32_t getObjectID() const
98        { return *(uint32_t*)(data_+2); }
99      inline void setObjectID(uint32_t objectID_)
100        { *(uint32_t*)(data_+2) = objectID_; }
101      inline void operator=(SynchronisableHeaderLight& h)
102        { memcpy(data_, h.data_, SynchronisableHeaderLight::getSize()); }
103  };
104 
105  typedef uint8_t VariableID;
106 
107  /**
108   * @brief: stores information about a Synchronisable
109   *
110   * This class stores the information about a Synchronisable (objectID_, classID_, contextID_, dataSize)
111   * in an emulated bitset.
112   * Bit 1 to 31 store the size of the Data the synchronisable consumes in the stream
113   * Bit 32 is a bool and defines whether the variables are stored in diff mode
114   * Byte 5 to 8: objectID_
115   * Byte 9 to 12: classID_
116   * Byte 13 to 16: contextID_
117   */
118  class _NetworkExport SynchronisableHeader: public SynchronisableHeaderLight
119  {
120    public:
121      SynchronisableHeader(uint8_t* data): SynchronisableHeaderLight(data)
122        {}
123      inline static uint32_t getSize()
124        { return SynchronisableHeaderLight::getSize()+8; }
125      inline uint32_t getClassID() const
126        { return *(uint32_t*)(data_+SynchronisableHeaderLight::getSize()); }
127      inline void setClassID(uint32_t classID_)
128        { *(uint32_t*)(data_+SynchronisableHeaderLight::getSize()) = classID_; }
129      inline uint32_t getContextID() const
130        { return *(uint32_t*)(data_+SynchronisableHeaderLight::getSize()+4); }
131      inline void setContextID(uint32_t contextID_)
132        { *(uint32_t*)(data_+SynchronisableHeaderLight::getSize()+4) = contextID_; }
133      inline void operator=(SynchronisableHeader& h)
134        { memcpy(data_, h.data_, getSize()); }
135  };
136 
137//   inline void operator=(SynchronisableHeaderLight& h1, SynchronisableHeader& h2)
138//   {
139//     memcpy(h1.data_, h2.data_, h1.getSize());
140//   }
141
142  /**
143  * This class is the base class of all the Objects in the universe that need to be synchronised over the network
144  * Every class, that inherits from this class has to link the DATA THAT NEEDS TO BE SYNCHRONISED into the linked list.
145  * @author Oliver Scheuss
146  */
147  class _NetworkExport Synchronisable : virtual public OrxonoxInterface {
148  public:
149    friend class packet::Gamestate;
150    virtual ~Synchronisable();
151
152    static void setClient(bool b);
153
154    static Synchronisable *fabricate(uint8_t*& mem, uint8_t mode=0x0);
155    static bool deleteObject(uint32_t objectID_);
156    static Synchronisable *getSynchronisable(uint32_t objectID_);
157    static unsigned int getNumberOfDeletedObject(){ return deletedObjects_.size(); }
158    static uint32_t popDeletedObject(){ uint32_t i = deletedObjects_.front(); deletedObjects_.pop(); return i; }
159
160    inline uint32_t getObjectID() const {return this->objectID_;}
161    inline unsigned int getContextID() const {return this->contextID_;}
162    inline uint32_t getClassID() const {return this->classID_;}
163    inline unsigned int getPriority() const { return this->objectFrequency_;}
164    inline uint8_t getSyncMode() const { return this->objectMode_; }
165
166    void setSyncMode(uint8_t mode);
167   
168    inline uint32_t getNrOfVariables(){ return this->syncList_.size(); }
169    inline uint32_t getVarSize( VariableID ID )
170    { return this->syncList_[ID]->getSize(state_); }
171
172  protected:
173    Synchronisable(Context* context);
174    template <class T> void registerVariable(T& variable, uint8_t mode=0x1, NetworkCallbackBase *cb=nullptr, bool bidirectional=false);
175    template <class T> void registerVariable(std::set<T>& variable, uint8_t mode=0x1, NetworkCallbackBase *cb=nullptr, bool bidirectional=false);
176    template <class T> void unregisterVariable(T& var);
177
178    void setPriority(unsigned int freq){ objectFrequency_ = freq; }
179    uint32_t findContextID(Context* context);
180
181  private:
182    uint32_t getData(uint8_t*& mem, std::vector<uint32_t>& sizes, int32_t id, uint8_t mode);
183    uint32_t getSize(int32_t id, uint8_t mode=0x0);
184    bool updateData(uint8_t*& mem, uint8_t mode=0x0, bool forceCallback=false);
185    bool doSync(/*int32_t id,*/ uint8_t mode=0x0);
186    bool doReceive( uint8_t mode );
187
188    inline void setObjectID(uint32_t id){ this->objectID_ = id; objectMap_[this->objectID_] = this; }
189    inline void setClassID(uint32_t id){ this->classID_ = id; }
190
191    uint32_t objectID_;
192    uint32_t contextID_;
193    uint32_t classID_;
194
195    std::vector<SynchronisableVariableBase*> syncList_;
196    std::vector<SynchronisableVariableBase*> stringList_;
197    uint32_t dataSize_; //size of all variables except strings
198    static uint8_t state_; // detemines wheter we are server (default) or client
199    bool backsync_; // if true the variables with mode > 1 will be synchronised to server (client -> server)
200    unsigned int objectFrequency_;
201    int objectMode_;
202    static std::map<uint32_t, Synchronisable *> objectMap_;
203    static std::queue<uint32_t> deletedObjects_;
204  };
205
206  namespace detail
207  {
208    template <class T, bool = std::is_enum<T>::value>
209    struct UnderlyingType;
210    template <class T>
211    struct UnderlyingType<T, true> { typedef typename std::underlying_type<T>::type type; };
212    template <class T>
213    struct UnderlyingType<T, false> { typedef T type; };
214  }
215
216  template <class T>
217  void Synchronisable::registerVariable(T& variable, uint8_t mode, NetworkCallbackBase *cb, bool bidirectional)
218  {
219    typedef typename detail::UnderlyingType<T>::type UnderlyingType;
220    if (bidirectional)
221    {
222      syncList_.push_back(new SynchronisableVariableBidirectional<UnderlyingType>(reinterpret_cast<UnderlyingType&>(variable), mode, cb));
223      this->dataSize_ += syncList_.back()->getSize(state_);
224    }
225    else
226    {
227      syncList_.push_back(new SynchronisableVariable<UnderlyingType>(reinterpret_cast<UnderlyingType&>(variable), mode, cb));
228      if ( this->state_ == mode )
229        this->dataSize_ += syncList_.back()->getSize(state_);
230    }
231  }
232 
233  template <class T>
234  void Synchronisable::unregisterVariable(T& variable)
235  {
236    std::vector<SynchronisableVariableBase*>::iterator it = syncList_.begin();
237    while(it!=syncList_.end())
238    {
239      if( ((*it)->getReference()) == &variable )
240      {
241        this->dataSize_ -= (*it)->getSize(Synchronisable::state_);
242        delete (*it);
243        syncList_.erase(it);
244        return;
245      }
246      else
247        it++;
248    }
249    orxout(internal_error, context::network) << "Tried to unregister not registered variable" << endl;
250    assert(false); //if we reach this point something went wrong:
251    // the variable has not been registered before
252  }
253
254  template <class T>
255  void Synchronisable::registerVariable( std::set<T>& variable, uint8_t mode, NetworkCallbackBase *cb, bool bidirectional)
256  {
257    typedef typename detail::UnderlyingType<T>::type UnderlyingType;
258    SynchronisableVariableBase* sv;
259    if (bidirectional)
260      sv = new SynchronisableVariableBidirectional<std::set<UnderlyingType>>(reinterpret_cast<std::set<UnderlyingType>&>(variable), mode, cb);
261    else
262      sv = new SynchronisableVariable<std::set<UnderlyingType>>(reinterpret_cast<std::set<UnderlyingType>&>(variable), mode, cb);
263    syncList_.push_back(sv);
264    stringList_.push_back(sv);
265  }
266
267  template <> _NetworkExport void Synchronisable::registerVariable( std::string& variable, uint8_t mode, NetworkCallbackBase *cb, bool bidirectional);
268//   template <class T> _NetworkExport void Synchronisable::registerVariable<std::set<T>>( std::set<T>& variable, uint8_t mode, NetworkCallbackBase *cb, bool bidirectional);
269  template <> _NetworkExport void Synchronisable::unregisterVariable( std::string& variable );
270
271
272}
273
274#endif /* _Synchronisable_H__ */
Note: See TracBrowser for help on using the repository browser.