Cafu Engine
EngineEntity.hpp
1 /*
2 Cafu Engine, http://www.cafu.de/
3 Copyright (c) Carsten Fuchs and other contributors.
4 This project is licensed under the terms of the MIT license.
5 */
6 
7 #ifndef CAFU_ENGINE_ENTITY_HPP_INCLUDED
8 #define CAFU_ENGINE_ENTITY_HPP_INCLUDED
9 
10 #include "../Games/PlayerCommand.hpp"
11 #include "Math3D/Vector3.hpp"
12 #include "Network/State.hpp"
13 #include "Templates/Pointer.hpp"
14 
15 
16 class NetDataT;
17 namespace cf { namespace GameSys { class EntityT; } }
18 
19 
21 {
22  public:
23 
24  /******************/
25  /*** Both Sides ***/
26  /******************/
27 
28  /// Returns the GameSys entity related to this EngineEntityT.
29  IntrusivePtrT<cf::GameSys::EntityT> GetEntity() const { return m_Entity; }
30 
31 
32  /*******************/
33  /*** Server Side ***/
34  /*******************/
35 
36  // Creates a new EngineEntityT, where 'Entity_' points to a formerly constructed GameEntityI
37  // and 'CreationFrameNr' is the number of the server frame for which this EngineEntityT is created.
38  // Server side EngineEntityT creation is always (and only) triggered by an EntityManagerT, either after a new world was loaded or
39  // when a game entity creates a new entity by calling GameWorld->CreateNewEntity() in its 'Think()' method.
40  EngineEntityT(IntrusivePtrT<cf::GameSys::EntityT> Ent, unsigned long CreationFrameNr);
41 
42  // Prepares the entity to enter the next state for frame 'ServerFrameNr'.
43  // This function must be called for each entity before any entities 'Think()' function is called.
44  // Reason: Any thinking entity may also (implicitly) modify *other* entities, e.g. by calling their 'TakeDamage()' functions.
45  // If such entities had not been previously prepared by this function, the implementation could not keep the state management right.
46  void PreThink(unsigned long ServerFrameNr);
47 
48  // Calculates the new state for the next frame 'ServerFrameNr', where 'FrameTime' seconds passed since the previous frame.
49  // Does nothing if the Entity was just new created for the frame 'ServerFrameNr', that is, CreationFrameNr>=ServerFrameNr.
50  // Do not use this method for client side prediction -- it will not work (before calling this method, calls to 'PreThink()'
51  // are required (as detailed above), which in turn maintain 'OldStates').
52  void Think(float FrameTime, unsigned long ServerFrameNr);
53 
54  // Schreibt die SC1_EntityBaseLine Message für diesen EngineEntityT nach 'OutDatas', falls 'SentClientBaseLineFrameNr' kleiner (d.h. älter)
55  // als die 'BaseLineFrameNr' dieses EngineEntityTs ist, d.h. falls dieser EngineEntityT neu erschaffen wurde und an den Client noch keine
56  // entsprechende SC1_EntityBaseLine Message geschickt wurde.
57  // 'SentClientBaseLineFrameNr' ist die FrameNr, bis zu der dem Client schon alle SC1_EntityBaseLine Messages gesandt wurden
58  // (heißt aber nicht, daß er die auch schon hat!). Unabhängig davon sollten die 'OutDatas' "reliable" verschickt werden.
59  void WriteNewBaseLine(unsigned long SentClientBaseLineFrameNr, ArrayT< ArrayT<char> >& OutDatas) const;
60 
61  // Schreibt eine SC1_EntityUpdate Message nach 'OutData'.
62  // Dabei wird der gegenwärtige 'Entity->State' gegen die BaseLine Delta-komprimiert, falls 'SendFromBaseLine==true',
63  // ansonsten gegen den Zustand des Frames mit der Nummer 'ClientFrameNr'.
64  // Wenn der Entity-State sich überhaupt nicht geändert hat und 'ForceInfo==false', wird überhaupt keine Nachricht generiert,
65  // ansonsten zumindest der Header der SC1_EntityUpdate Message.
66  // Gibt 'true' bei Erfolg zurück, sonst 'false'. Der einzige Möglichkeit, weswegen diese Funktion scheitern kann ('false'),
67  // ist 'SendFromBaseLine==false' und eine zu kleine 'ClientFrameNr' (verlangt eine Komprimierung gegen etwas, was wir nicht (mehr) haben).
68  // Im Falle des Scheiterns bleibt 'OutData' unberührt.
69  bool WriteDeltaEntity(bool SendFromBaseLine, unsigned long ClientFrameNr, NetDataT& OutData, bool ForceInfo) const;
70 
71 
72  /*******************/
73  /*** Client Side ***/
74  /*******************/
75 
76  // This creates a new EngineEntityT by taking a IntrusivePtrT<GameEntityI>, which previously must have been properly constructed from
77  // the former parts of the SC1_EntityBaseLine in InData. It then fully constructs it by updating its non-initialized 'Entity_->State'
78  // with the rest of the SC1_EntityBaseLine message.
80 
81  // Ausgehend vom (alten) Zustand des Frames 'DeltaFrameNr' wird der Entity Zustand des (neuen) Frames 'ServerFrameNr' bestimmt,
82  // wobei Delta-Informationen anhand der DeltaMessage eingebracht werden.
83  // 'DeltaFrameNr' ist die Nummer des Frames, gegen dessen Zustand Delta-dekomprimiert werden soll.
84  // Ist dieser Parameter 0, so wird angenommen, daß DeltaMessage gegen die BaseLine angewandt werden sollen!
85  // Gibt 'true' bei Erfolg zurück, sonst (Scheitern) 'false'.
86  // Die Funktion scheitert bei "unpassenden" Parametern (wenn 'DeltaFrameNr<=EntityStateFrameNr<ServerFrameNr' verletzt ist)
87  // und wenn 'DeltaFrameNr' zu alt ist (Versuch, gegen etwas zu Dekomprimieren, was wir nicht (mehr) haben).
88  // Im Falle des Scheitersn bleibt die EngineEntityT Instanz unberührt.
89  bool ParseServerDeltaUpdateMessage(unsigned long DeltaFrameNr, unsigned long ServerFrameNr, const ArrayT<uint8_t>* DeltaMessage);
90 
91  /// Updates the (predicted) state of this entity according to the `PlayerCommand`.
92  void Predict(const PlayerCommandT& PlayerCommand);
93 
94 
95  private:
96 
97  EngineEntityT(const EngineEntityT&); ///< Use of the Copy Constructor is not allowed.
98  void operator = (const EngineEntityT&); ///< Use of the Assignment Operator is not allowed.
99 
100  /// Returns the serialized state of our Entity.
101  cf::Network::StateT GetState() const;
102 
103  /// Sets the state of our Entity to the given State.
104  /// @param State The state to assign to the entity.
105  /// @param IsIniting Used to indicate that the call is part of the construction / first-time
106  /// initialization of the entity. The implementation will use this to not wrongly process
107  /// the event counters or to interpolate from stale values.
108  void SetState(const cf::Network::StateT& State, bool IsIniting=false) const;
109 
110 
111  IntrusivePtrT<cf::GameSys::EntityT> m_Entity; ///< The game entity. On the client, it is in the most recent state as received from the server, *plus* any extrapolations (NPCs) and predictions (local human player) that are applied until the next update arrives.
112 
113  unsigned long EntityStateFrameNr; ///< `== ServerFrameNr` (the state number of Entity->State), used both on Client and Server side.
114 
115  cf::Network::StateT m_BaseLine; ///< State of the entity immediately after it was created.
116  const unsigned long m_BaseLineFrameNr; ///< Frame number on which the entity was created. Only used on the server, unused on the client.
117  ArrayT<cf::Network::StateT> m_OldStates; ///< States of the last n (server) frames, kept on both client and server side for delta compression.
118 };
119 
120 #endif
Definition: EngineEntity.hpp:20
This struct represents per-frame player inputs for controlling human player entities.
Definition: PlayerCommand.hpp:32
void Predict(const PlayerCommandT &PlayerCommand)
Updates the (predicted) state of this entity according to the PlayerCommand.
Definition: EngineEntity.cpp:247
IntrusivePtrT< cf::GameSys::EntityT > GetEntity() const
Returns the GameSys entity related to this EngineEntityT.
Definition: EngineEntity.hpp:29
Class that allows easy and portable handling, sending and receiving of data over a network...
Definition: Network.hpp:181
This class holds the serialized state of another object (typically a game entity).
Definition: State.hpp:46
Definition: Renderer.hpp:16