Leviathan  0.8.0.0
Leviathan game engine
StateHolder.h
Go to the documentation of this file.
1 // Leviathan Game Engine
2 // Copyright (c) 2012-2019 Henri Hyyryläinen
3 #pragma once
4 #include "Define.h"
5 // ------------------------------------ //
6 #include "Common/ObjectPool.h"
7 #include "Common/SFMLPackets.h"
8 #include "EntityCommon.h"
9 
10 #include <array>
11 #include <memory>
12 
13 namespace Leviathan {
14 
18 constexpr auto KEPT_STATES_COUNT = 5;
19 
20 template<class StateT>
21 class StateHolder;
22 
24 template<class StateT>
26 public:
28  StateT* GetNewest() const
29  {
30  StateT* newest = nullptr;
31  float highest = 0;
32 
33  for(StateT* state : StoredStates) {
34 
35  if(state && state->StateTime >= highest) {
36 
37  newest = state;
38  highest = state->StateTime;
39  }
40  }
41 
42  return newest;
43  }
44 
46  StateT* GetOldest() const
47  {
48  StateT* oldest = nullptr;
49  float lowest = std::numeric_limits<float>::max();
50 
51  for(StateT* state : StoredStates) {
52 
53  if(state && state->StateTime <= lowest) {
54 
55  oldest = state;
56  lowest = state->StateTime;
57  }
58  }
59 
60  return oldest;
61  }
62 
68  StateT* GetNewer(float time) const
69  {
70  StateT* closest = nullptr;
71  float closestBy = std::numeric_limits<float>::max();
72 
73  for(StateT* state : StoredStates) {
74 
75  if(!state || state->StateTime <= time)
76  continue;
77 
78  const auto difference = state->StateTime - time;
79  if(difference <= closestBy) {
80 
81  closestBy = difference;
82  closest = state;
83  }
84  }
85 
86  return closest;
87  }
88 
90  StateT* GetState(float time) const
91  {
92  for(StateT* state : StoredStates) {
93 
94  if(state && state->StateTime == time)
95  return state;
96  }
97 
98  return nullptr;
99  }
100 
102  bool IsStateValid(StateT* statetocheck) const
103  {
104  for(StateT* state : StoredStates) {
105  if(state == statetocheck)
106  return true;
107  }
108 
109  return false;
110  }
111 
115  void Append(StateT* newstate, StateHolder<StateT>& stateowner)
116  {
117  // Fill from the back and pop from the front if states don't fit //
118 
119  // This would only speed up the first added state, so maybe the performance
120  // is better if we skip this check
121  // if(StoredStates[KEPT_STATES_COUNT - 1] == nullptr){
122 
123  // StoredStates[KEPT_STATES_COUNT - 1] = newstate;
124  // return;
125  // }
126 
127  // First state will be popped off if it exists //
128  if(StoredStates[0] != nullptr) {
129 
130  stateowner._DestroyStateObject(StoredStates[0]);
131  }
132 
133  for(size_t i = 0; i < KEPT_STATES_COUNT - 1; ++i) {
134 
135  StoredStates[i] = StoredStates[i + 1];
136  }
137 
138  StoredStates[KEPT_STATES_COUNT - 1] = newstate;
139  }
140 
143  auto GetNumberOfStates() const
144  {
145  int count = 0;
146 
147  for(StateT* state : StoredStates) {
148 
149  if(state)
150  ++count;
151  }
152 
153  return count;
154  }
155 
156 protected:
157  std::array<StateT*, KEPT_STATES_COUNT> StoredStates;
158 };
159 
162 template<class StateT>
163 class StateHolder {
165 
166 public:
168 
170  {
171  // Both of the pools are released here so the destructor of ObjectsComponentStates
172  // doesn't need to notify us of the states it held
173  }
174 
177  template<class ComponentT>
178  bool CreateStateIfChanged(ObjectID id, const ComponentT& component, float time)
179  {
180  auto entityStates = GetStateFor(id);
181 
182  // Get latest state to compare current values against //
183  StateT* latestState = entityStates->GetNewest();
184 
185  // If empty always create //
186  if(!latestState) {
187 
188  StateT* newState = _CreateNewState(time, component);
189  entityStates->Append(newState, *this);
190  return true;
191  }
192 
193  // Check is the latest state still correct //
194  if(latestState->DoesMatchState(component))
195  return false;
196 
197  // Create a new state //
198  StateT* newState = _CreateNewState(time, component);
199  entityStates->Append(newState, *this);
200  return true;
201  }
202 
204  void DeserializeState(ObjectID id, float time, sf::Packet& data, float referencestatestime)
205  {
206  auto entityStates = GetStateFor(id);
207 
208  this->_DeserializeState(entityStates, id, time, data, referencestatestime);
209  }
210 
213  template<class ComponentT>
214  void DeserializeAndApplyState(ObjectID id, ComponentT& component, float time,
215  sf::Packet& data, float referencestatestime)
216  {
217  auto entityStates = GetStateFor(id);
218 
219  // Deserialize
220  auto* deserialized =
221  this->_DeserializeState(entityStates, id, time, data, referencestatestime);
222 
223  if(!deserialized) {
224  LOG_ERROR("StateHolder: failed to deserialize state");
225  return;
226  }
227 
228  // And apply it if it is newest
229  auto* newest = entityStates->GetNewest();
230 
231  if(deserialized == newest) {
232 
233  component.ApplyState(*newest);
234  } else {
235  float newestNumber = newest ? newest->StateTime : -1;
236 
237  LOG_WARNING("StateHolder: DeserializeAndApplyState: received not the newest "
238  "packet, received: " +
239  std::to_string(deserialized->StateTime) +
240  ", newest: " + std::to_string(newestNumber));
241  }
242  }
243 
245  template<class ComponentT>
246  StateT CreateStateForSending(const ComponentT& component, float time) const
247  {
248  return StateT(time, component);
249  }
250 
251 
254  {
255  return StateObjects.GetObjectCount();
256  }
257 
260  {
261  return StateObjects.Find(id);
262  }
263 
264 protected:
266  float time, sf::Packet& data, float referencestatestime)
267  {
268  StateT* reference = nullptr;
269 
270  if(referencestatestime >= 0.f) {
271  reference = entityStates->GetState(referencestatestime);
272 
273  if(!reference) {
274 
275  LOG_WARNING("StateHolder: DeserializeState: can't find reference tick: " +
276  std::to_string(referencestatestime) +
277  " for entity: " + std::to_string(id));
278 
279  reference = entityStates->GetNewest();
280  }
281  }
282 
283  // Create a new state //
284  StateT* newState = _CreateNewState(reference, data);
285 
286  // This can't be deserialized from data so we forward it
287  newState->StateTime = time;
288 
289  // TODO: do we need to check whether the states already contain a state for this time
290  entityStates->Append(newState, *this);
291  return newState;
292  }
293 
295  {
296  ObjectsComponentStates<StateT>* entityStates = StateObjects.Find(id);
297 
298  if(!entityStates) {
299 
300  entityStates = StateObjects.ConstructNew(id);
301  }
302 
303  return entityStates;
304  }
305 
306  template<typename... Args>
307  StateT* _CreateNewState(Args&&... args)
308  {
309  return StatePool.ConstructNew(std::forward<Args>(args)...);
310  }
311 
312  void _DestroyStateObject(StateT* state)
313  {
314  StatePool.Destroy(state);
315  }
316 
317 private:
320 
323  BasicPool<StateT> StatePool;
324 };
325 
326 } // namespace Leviathan
bool CreateStateIfChanged(ObjectID id, const ComponentT &component, float time)
Creates a new state for entity's component if it has changed.
Definition: StateHolder.h:178
int32_t ObjectID
Definition: EntityCommon.h:11
#define LOG_ERROR(x)
Definition: Define.h:92
void DeserializeState(ObjectID id, float time, sf::Packet &data, float referencestatestime)
Deserializes a state for entity's component from an archive.
Definition: StateHolder.h:204
void DeserializeAndApplyState(ObjectID id, ComponentT &component, float time, sf::Packet &data, float referencestatestime)
Deserializes a state for entity's component from an archive and applies it if it is the newest.
Definition: StateHolder.h:214
auto GetNumberOfEntitiesWithStates() const
Returns the number of entities that have states.
Definition: StateHolder.h:253
StateT CreateStateForSending(const ComponentT &component, float time) const
Creates a state object for sending.
Definition: StateHolder.h:246
#define LOG_WARNING(x)
Definition: Define.h:91
constexpr auto KEPT_STATES_COUNT
Definition: StateHolder.h:18
void Append(StateT *newstate, StateHolder< StateT > &stateowner)
Appends a new state removing old states if they don't fit anymore.
Definition: StateHolder.h:115
void Destroy(ElementType *element)
Destroys a created element.
Definition: ObjectPool.h:62
StateT * _DeserializeState(ObjectsComponentStates< StateT > *entityStates, ObjectID id, float time, sf::Packet &data, float referencestatestime)
Definition: StateHolder.h:265
auto GetNumberOfStates() const
Counts the filled number of state slots.
Definition: StateHolder.h:143
StateT * GetState(float time) const
Returns state matching the time.
Definition: StateHolder.h:90
StateT * GetNewest() const
Returns the state with the time.
Definition: StateHolder.h:28
void _DestroyStateObject(StateT *state)
Definition: StateHolder.h:312
std::array< StateT *, KEPT_STATES_COUNT > StoredStates
Definition: StateHolder.h:157
bool IsStateValid(StateT *statetocheck) const
Returns true if state is still valid.
Definition: StateHolder.h:102
StateT * GetOldest() const
Returns the state with the lowest time.
Definition: StateHolder.h:46
StateT * GetNewer(float time) const
Returns the state with closest time that is higher.
Definition: StateHolder.h:68
Holds state objects of type StateT related to a single entity.
Definition: StateHolder.h:25
ObjectsComponentStates< StateT > * GetStateFor(ObjectID id)
Definition: StateHolder.h:294
StateT * _CreateNewState(Args &&... args)
Definition: StateHolder.h:307
ObjectsComponentStates< StateT > const * GetEntityStates(ObjectID id) const
Returns a pointer to entity's states if they exist.
Definition: StateHolder.h:259
ElementType * ConstructNew(Args &&... args)
Constructs a new component of the held type for entity.
Definition: ObjectPool.h:40
Holds state objects of type for quick access by ObjectID.
Definition: GameWorld.h:31
The access mask controls which registered functions and classes a script sees.
Definition: GameModule.h:12
Creates objects in a shared memory region.
Definition: ObjectPool.h:93