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-2018 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 
16 constexpr auto KEPT_STATES_COUNT = 5;
17 
18 template<class StateT>
19 class StateHolder;
20 
22 template<class StateT>
24 public:
26  StateT* GetNewest() const
27  {
28  StateT* newest = nullptr;
29  int newestTick = 0;
30 
31  for(StateT* state : StoredStates) {
32 
33  if(state && state->TickNumber >= newestTick) {
34 
35  newest = state;
36  newestTick = state->TickNumber;
37  }
38  }
39 
40  return newest;
41  }
42 
44  StateT* GetOldest() const
45  {
46  StateT* oldest = nullptr;
47  int oldestTick = std::numeric_limits<int>::max();
48 
49  for(StateT* state : StoredStates) {
50 
51  if(state && state->TickNumber <= oldestTick) {
52 
53  oldest = state;
54  oldestTick = state->TickNumber;
55  }
56  }
57 
58  return oldest;
59  }
60 
67  StateT* GetMatchingOrNewer(int ticknumber) const
68  {
69  StateT* closest = nullptr;
70  int closestBy = std::numeric_limits<int>::max();
71 
72  for(StateT* state : StoredStates) {
73 
74  if(!state || state->TickNumber < ticknumber)
75  continue;
76 
77  if(state->TickNumber == ticknumber) {
78 
79  return state;
80  }
81 
82  const auto difference = state->TickNumber - ticknumber;
83  if(difference <= closestBy) {
84 
85  closestBy = difference;
86  closest = state;
87  }
88  }
89 
90  return closest;
91  }
92 
94  StateT* GetState(int ticknumber) const
95  {
96  for(StateT* state : StoredStates) {
97 
98  if(state && state->TickNumber == ticknumber)
99  return state;
100  }
101 
102  return nullptr;
103  }
104 
106  bool IsStateValid(StateT* statetocheck) const
107  {
108  for(StateT* state : StoredStates) {
109  if(state == statetocheck)
110  return true;
111  }
112 
113  return false;
114  }
115 
119  void Append(StateT* newstate, StateHolder<StateT>& stateowner)
120  {
121  // Fill from the back and pop from the front if states don't fit //
122 
123  // This would only speed up the first added state, so maybe the performance
124  // is better if we skip this check
125  // if(StoredStates[KEPT_STATES_COUNT - 1] == nullptr){
126 
127  // StoredStates[KEPT_STATES_COUNT - 1] = newstate;
128  // return;
129  // }
130 
131  // First state will be popped off if it exists //
132  if(StoredStates[0] != nullptr) {
133 
134  stateowner._DestroyStateObject(StoredStates[0]);
135  }
136 
137  for(size_t i = 0; i < KEPT_STATES_COUNT - 1; ++i) {
138 
139  StoredStates[i] = StoredStates[i + 1];
140  }
141 
142  StoredStates[KEPT_STATES_COUNT - 1] = newstate;
143  }
144 
147  auto GetNumberOfStates() const
148  {
149  int count = 0;
150 
151  for(StateT* state : StoredStates) {
152 
153  if(state)
154  ++count;
155  }
156 
157  return count;
158  }
159 
160 protected:
161  std::array<StateT*, KEPT_STATES_COUNT> StoredStates;
162 };
163 
166 template<class StateT>
167 class StateHolder {
169 
170 public:
172 
174  {
175  // Both of the pools are released here so the destructor of ObjectsComponentStates
176  // doesn't need to notify us of the states it held
177  }
178 
181  template<class ComponentT>
182  bool CreateStateIfChanged(ObjectID id, const ComponentT& component, int ticknumber)
183  {
184  auto entityStates = GetStateFor(id);
185 
186  // Get latest state to compare current values against //
187  StateT* latestState = entityStates->GetNewest();
188 
189  // If empty always create //
190  if(!latestState) {
191 
192  StateT* newState = _CreateNewState(ticknumber, component);
193  entityStates->Append(newState, *this);
194  return true;
195  }
196 
197  // Check is the latest state still correct //
198  if(latestState->DoesMatchState(component))
199  return false;
200 
201  // Create a new state //
202  StateT* newState = _CreateNewState(ticknumber, component);
203  entityStates->Append(newState, *this);
204  return true;
205  }
206 
209  ObjectID id, int32_t ticknumber, sf::Packet& data, int32_t referencetick)
210  {
211  auto entityStates = GetStateFor(id);
212 
213  this->_DeserializeState(entityStates, id, ticknumber, data, referencetick);
214  }
215 
218  template<class ComponentT>
219  void DeserializeAndApplyState(ObjectID id, ComponentT& component, int32_t ticknumber,
220  sf::Packet& data, int32_t referencetick)
221  {
222  auto entityStates = GetStateFor(id);
223 
224  // Deserialize
225  auto* deserialized =
226  this->_DeserializeState(entityStates, id, ticknumber, data, referencetick);
227 
228  if(!deserialized) {
229  LOG_ERROR("StateHolder: failed to deserialize state");
230  return;
231  }
232 
233  // And apply it if it is newest
234  auto* newest = entityStates->GetNewest();
235 
236  if(deserialized == newest) {
237 
238  component.ApplyState(*newest);
239  } else {
240  int newestNumber = newest ? newest->TickNumber : -1;
241 
242  LOG_WARNING("StateHolder: DeserializeAndApplyState: received not the newest "
243  "packet, received: " +
244  std::to_string(deserialized->TickNumber) +
245  ", newest: " + std::to_string(newestNumber));
246  }
247  }
248 
250  template<class ComponentT>
251  StateT CreateStateForSending(const ComponentT& component, int ticknumber) const
252  {
253  return StateT(ticknumber, component);
254  }
255 
256 
259  {
260  return StateObjects.GetObjectCount();
261  }
262 
265  {
266  return StateObjects.Find(id);
267  }
268 
269 protected:
271  int32_t ticknumber, sf::Packet& data, int32_t referencetick)
272  {
273  StateT* reference = nullptr;
274 
275  if(referencetick != -1) {
276  reference = entityStates->GetState(referencetick);
277 
278  if(!reference) {
279 
280  LOG_WARNING("StateHolder: DeserializeState: can't find reference tick: " +
281  std::to_string(referencetick) +
282  " for entity: " + std::to_string(id));
283 
284  reference = entityStates->GetNewest();
285  }
286  }
287 
288  // Create a new state //
289  StateT* newState = _CreateNewState(reference, data);
290 
291  // This can't be deserialized from data so we forward it
292  newState->TickNumber = ticknumber;
293 
294  // TODO: do we need to check whether the states already contain a state for this
295  // tick?
296  entityStates->Append(newState, *this);
297  return newState;
298  }
299 
301  {
302  ObjectsComponentStates<StateT>* entityStates = StateObjects.Find(id);
303 
304  if(!entityStates) {
305 
306  entityStates = StateObjects.ConstructNew(id);
307  }
308 
309  return entityStates;
310  }
311 
312  template<typename... Args>
313  StateT* _CreateNewState(Args&&... args)
314  {
315  return StatePool.ConstructNew(std::forward<Args>(args)...);
316  }
317 
318  void _DestroyStateObject(StateT* state)
319  {
320  StatePool.Destroy(state);
321  }
322 
323 private:
326 
329  BasicPool<StateT> StatePool;
330 };
331 
332 } // namespace Leviathan
bool CreateStateIfChanged(ObjectID id, const ComponentT &component, int ticknumber)
Creates a new state for entity&#39;s component if it has changed.
Definition: StateHolder.h:182
void DeserializeAndApplyState(ObjectID id, ComponentT &component, int32_t ticknumber, sf::Packet &data, int32_t referencetick)
Deserializes a state for entity&#39;s component from an archive and applies it if it is the newest...
Definition: StateHolder.h:219
StateT CreateStateForSending(const ComponentT &component, int ticknumber) const
Creates a state object for sending.
Definition: StateHolder.h:251
StateT * _DeserializeState(ObjectsComponentStates< StateT > *entityStates, ObjectID id, int32_t ticknumber, sf::Packet &data, int32_t referencetick)
Definition: StateHolder.h:270
int32_t ObjectID
Definition: EntityCommon.h:11
#define LOG_ERROR(x)
Definition: Define.h:84
auto GetNumberOfEntitiesWithStates() const
Returns the number of entities that have states.
Definition: StateHolder.h:258
#define LOG_WARNING(x)
Definition: Define.h:83
StateT * GetMatchingOrNewer(int ticknumber) const
Returns the state matching the tick number or the closest tick that is higher than the tick number...
Definition: StateHolder.h:67
constexpr auto KEPT_STATES_COUNT
Number of states that are kept. Corresponds to time span of TICKSPEED * KEPT_STATES_COUNT.
Definition: StateHolder.h:16
void Append(StateT *newstate, StateHolder< StateT > &stateowner)
Appends a new state removing old states if they don&#39;t fit anymore.
Definition: StateHolder.h:119
void Destroy(ElementType *element)
Destroys a created element.
Definition: ObjectPool.h:62
auto GetNumberOfStates() const
Counts the filled number of state slots.
Definition: StateHolder.h:147
StateT * GetNewest() const
Returns the state with the highest tick number.
Definition: StateHolder.h:26
void _DestroyStateObject(StateT *state)
Definition: StateHolder.h:318
void DeserializeState(ObjectID id, int32_t ticknumber, sf::Packet &data, int32_t referencetick)
Deserializes a state for entity&#39;s component from an archive.
Definition: StateHolder.h:208
std::array< StateT *, KEPT_STATES_COUNT > StoredStates
Definition: StateHolder.h:161
bool IsStateValid(StateT *statetocheck) const
Returns true if state is still valid.
Definition: StateHolder.h:106
StateT * GetOldest() const
Returns the state with the lowest tick number.
Definition: StateHolder.h:44
Holds state objects of type StateT related to a single entity.
Definition: StateHolder.h:23
ObjectsComponentStates< StateT > * GetStateFor(ObjectID id)
Definition: StateHolder.h:300
StateT * GetState(int ticknumber) const
Returns state matching tick number.
Definition: StateHolder.h:94
StateT * _CreateNewState(Args &&... args)
Definition: StateHolder.h:313
ObjectsComponentStates< StateT > const * GetEntityStates(ObjectID id) const
Returns a pointer to entity&#39;s states if they exist.
Definition: StateHolder.h:264
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:36
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