Emergency 20 Dokumentation  4.2.0
DataCacheComponentExistenceTrackingBase-inl.h
Go to the documentation of this file.
1 // Copyright (C) 2012-2018 Promotion Software GmbH
2 
3 
4 //[-------------------------------------------------------]
5 //[ Includes ]
6 //[-------------------------------------------------------]
8 
9 #include <qsf/map/Entity.h>
11 #include <qsf/time/clock/Clock.h>
12 
13 
14 //[-------------------------------------------------------]
15 //[ Namespace ]
16 //[-------------------------------------------------------]
17 namespace em5
18 {
19  namespace multiplayer
20  {
21 
22 
23  //[-------------------------------------------------------]
24  //[ Public methods ]
25  //[-------------------------------------------------------]
26  template<class TrackedComponentType>
28  DataCacheBase(entity),
29  mComponentChangeCounter(0),
30  mNoDestruction(noDestruction),
31  mEntityHasComponentFromStream(false),
32  mEntityHasComponent(false),
33  mComponentExistenceChanged(false)
34  {
35  mComponentChangeCounter = entity.getComponentChangesCount();
36  mComponent = entity.getComponent<TrackedComponentType>();
37  mEntityHasComponent = mComponent.valid();
38  }
39 
40 
41  //[-------------------------------------------------------]
42  //[ Public virtual em5::multiplayer::DataCacheBase methods ]
43  //[-------------------------------------------------------]
44  template<class TrackedComponentType>
46  {
47  if (mComponentChangeCounter != targetEntity.getComponentChangesCount())
48  {
49  mComponentChangeCounter = targetEntity.getComponentChangesCount();
50  // TODO(sw) Could we avoid to call getComponent here? Because this part is called in every tick
51  // The case when an existing component gets destroy can be handled via checking the weakptr.
52  // But how do the check in a better way (performance wise) to find out if a component got created in the entity?
53  TrackedComponentType* component = targetEntity.getComponent<TrackedComponentType>();
54 
55  if (nullptr == component && mEntityHasComponent)
56  {
57  // The entity lost its component since last update
58  mComponentExistenceChanged = true;
59  mEntityHasComponent = false;
60  }
61  else if (nullptr != component && !mEntityHasComponent)
62  {
63  // The entity got its component since last update
64  mEntityHasComponent = true;
65  mComponentExistenceChanged = true;
66  }
67  else
68  {
69  // Noting has changed so save that
70  mComponentExistenceChanged = false;
71  mEntityHasComponent = nullptr != component;
72  }
73 
74  mComponent = component;
75  }
76  else
77  {
78  mComponentExistenceChanged = false;
79  }
80 
81  return mComponentExistenceChanged;
82  }
83 
84  template<class TrackedComponentType>
86  {
87  // Write if the component existence has changed
88  bitStream.write(mComponentExistenceChanged);
89 
90  // Write component existence. This values is always needed for the client side, when it reads the data from the stream
91  bitStream.write(mEntityHasComponent);
92  }
93 
94  template<class TrackedComponentType>
96  {
97  // When this method is called at least one tracked data by this class has changed on the host side
98 
99  // Read if the component existence has changed
100  if (!bitStream.read(mComponentExistenceChanged))
101  {
102  QSF_ERROR("DataCacheComponentExistenceTrackingBase: Could not read the component existence state for the entity \"" << mEntityId << "\" from the data stream", return);
103  }
104 
105  // Read component existence
106  if (!bitStream.read(mEntityHasComponentFromStream))
107  {
108  QSF_ERROR("DataCacheComponentExistenceTrackingBase: Could not read if component exists for the entity \"" << mEntityId << "\" from the data stream", return);
109  }
110 
111  if (mComponentExistenceChanged)
112  {
113  HistoryEntry entry;
114  entry.tickCount = receivedHostTickCount;
115  entry.mEntityHasComponent = mEntityHasComponentFromStream;
116  entry.mComponentExistenceChanged = mComponentExistenceChanged;
117  mHistoryList.emplace_back(entry);
118  }
119  }
120 
121  template<class TrackedComponentType>
123  {
124  if (!mHistoryList.empty())
125  {
126  auto iterator = mHistoryList.begin();
127  while (iterator != mHistoryList.end())
128  {
129  const HistoryEntry& entry = *iterator;
130  if (entry.tickCount == clock.getSignalCounter())
131  {
132  // Store the value in a additional variable, because the derived class needs to access this value
133  mEntityHasComponent = entry.mEntityHasComponent;
134  mComponentExistenceChanged = entry.mComponentExistenceChanged;
135 
136  if (entry.mEntityHasComponent)
137  {
138  // The stream says that the entity should have the component now -> make it happen
139  mComponent = targetEntity.getOrCreateComponent<TrackedComponentType>();
140  }
141  else if (!mNoDestruction)
142  {
143  // The stream says that the entity should not have the component now -> make it happen
144  targetEntity.destroyComponent<TrackedComponentType>();
145  mComponent.clear();
146  }
147 
148  iterator = mHistoryList.erase(iterator);
149  }
150  else
151  {
152  // The entry is not for the current tick -> no further processing possible
153  return;
154  }
155  }
156  }
157  }
158 
159 
160  //[-------------------------------------------------------]
161  //[ Protected methods ]
162  //[-------------------------------------------------------]
163  template<class TrackedComponentType>
165  {
166  return mComponent.get();
167  }
168 
169  template<class TrackedComponentType>
171  {
172  return mEntityHasComponentFromStream;
173  }
174 
175  template<class TrackedComponentType>
177  {
178  return mEntityHasComponent;
179  }
180 
181  template<class TrackedComponentType>
183  {
184  return mComponentExistenceChanged;
185  }
186 
187 
188 //[-------------------------------------------------------]
189 //[ Namespace ]
190 //[-------------------------------------------------------]
191  } // multiplayer
192 } // em5
Definition: ActionPriority.h:13
EMERGENCY 5 multiplayer data cache base class.
Definition: DataCacheBase.h:48
bool hasEntityComponent()
Definition: DataCacheComponentExistenceTrackingBase-inl.h:176
TrackedComponentType * getComponent(const qsf::Entity &entity)
Definition: DataCacheComponentExistenceTrackingBase-inl.h:164
Entity class.
Definition: Entity.h:46
Clock class.
Definition: Clock.h:33
int getSignalCounter() const
Definition: Clock-inl.h:56
virtual bool prepareForUpdate(const qsf::Entity &targetEntity, const qsf::Clock &clock) override
Prepares for an update.
Definition: DataCacheComponentExistenceTrackingBase-inl.h:45
DataCacheComponentExistenceTrackingBase(const qsf::Entity &entity, bool noDestruction=false)
Constructor.
Definition: DataCacheComponentExistenceTrackingBase-inl.h:27
Game bit stream class (just a wrapper for linnet bit stream)
Definition: BitStream.h:40
bool hasComponentExistenceChanged()
Definition: DataCacheComponentExistenceTrackingBase-inl.h:182
virtual void setData(const qsf::game::BitStream &bitStream, const int32 receivedHostTickCount) override
Reads the data from the bit stream.
Definition: DataCacheComponentExistenceTrackingBase-inl.h:95
virtual void updateData(qsf::game::BitStream &bitStream, bool force) override
Updates the cache and writes any changed data to the given bit stream.
Definition: DataCacheComponentExistenceTrackingBase-inl.h:85
bool read(bool &value) const
signed int int32
Definition: PlatformTypes.h:180
bool valid() const
Check if this instance contains is a valid pointer.
Definition: WeakPtr-inl.h:20
void write(bool value)
#define QSF_ERROR(explanation, reaction)
Definition: ErrorHandling.h:132
uint8 getComponentChangesCount() const
Definition: Prototype-inl.h:117
virtual void interpolate(qsf::Entity &targetEntity, const qsf::Clock &clock, const int32 receivedHostTickCount) override
Does any interpolation steps needed to apply the cached data to the entity.
Definition: DataCacheComponentExistenceTrackingBase-inl.h:122
bool destroyComponent(Component &component)
Destroy a component instance.
T * getComponent() const
Return a component instance of a certain type.
Definition: Prototype-inl.h:63
bool hasEntityComponentFromStream()
Definition: DataCacheComponentExistenceTrackingBase-inl.h:170
T * getOrCreateComponent(bool startup=true)
Return a component instance of a certain type, creates an component instance in case it does not exis...
Definition: Prototype-inl.h:82