PageRenderTime 47ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/Core/Dependencies/Engine/MultiplayerOnline/RakNet/GameObjectReplica.cpp

https://bitbucket.org/barakianc/nvidia-physx-and-apex-in-gge
C++ | 958 lines | 604 code | 144 blank | 210 comment | 103 complexity | dfe1d2f3d05049e8211644d998ab53f1 MD5 | raw file
  1. #include "StdAfx.h"
  2. #include <string>
  3. #include <iostream>
  4. #ifdef HAVOK
  5. #include "GameObjectReplica.h"
  6. //#include "HavokNetManager.h"
  7. using namespace std;
  8. namespace GamePipeGame
  9. {
  10. ofstream outputLog;
  11. /// HavokObjectUpdateTest - Determines whether an object's properties are significantly different, and thus should be updated
  12. ///
  13. /// Parameters:
  14. /// p1, p2 - position vectors
  15. /// v1, v2 - velocity vectors
  16. /// av1, av2 - angular velocity vectors
  17. /// o1, o2 - orientation quaternions
  18. /// t - a magnitude tolerance
  19. /// rt - an angular tolerance (in radians)
  20. bool HavokObjectUpdateTest(Ogre::Vector3 p1, Ogre::Vector3 p2, Ogre::Vector3 v1, Ogre::Vector3 v2, Ogre::Vector3 av1,
  21. Ogre::Vector3 av2, Ogre::Quaternion o1, Ogre::Quaternion o2, Ogre::Real t, Ogre::Radian rt)
  22. {
  23. // check if the positions are different
  24. if(!p1.positionEquals(p2))
  25. return true;
  26. // check if the orientations are different, by more than rt
  27. if(!o1.equals(o2, rt))
  28. return true;
  29. // check if the velocity vectors are pointing in different directions, by more than rt
  30. if(!v1.normalisedCopy().directionEquals(v2.normalisedCopy(), rt))
  31. return true;
  32. // check if the angular velocity vectors are pointing in different directions, by more than rt
  33. if(!av1.normalisedCopy().directionEquals(av2.normalisedCopy(), rt))
  34. return true;
  35. // check if the difference between the squared linear speeds is more than t
  36. if(Ogre::Math::Abs(v1.squaredLength() - v2.squaredLength()) > t)
  37. return true;
  38. // check if the difference between the squared angular speeds is more than t
  39. if(Ogre::Math::Abs(av1.squaredLength() - av2.squaredLength()) > t)
  40. return true;
  41. return false;
  42. }
  43. /// GameObjectReplica - Constructor
  44. GameObjectReplica::GameObjectReplica()
  45. : BasicReplica(),
  46. havokGameObject(NULL),
  47. m_sHKXFileName(""),
  48. m_eGameObjectType(0),
  49. angularVelocity(Ogre::Vector3::ZERO), realAngularVelocity(Ogre::Vector3::ZERO),
  50. sceneManager(NULL), owningManager(NULL),
  51. useServerPhysicsOnly(false),
  52. currentAnimation("None")
  53. {
  54. }
  55. /// GameObjectReplica - Constructor
  56. ///
  57. /// Parameters:
  58. /// newName - a name for this object. Does not have to be unique.
  59. /// newMesh - the filename of the mesh for this object. Default value is empty.
  60. /// newEntity - an entity name for this object, which would likely be determined later anyway. Default value is empty.
  61. /// newMass - a value for an object's weight. Default value is zero.
  62. GameObjectReplica::GameObjectReplica(Ogre::String newName, Ogre::String newMesh, Ogre::String newEntity, Ogre::Real newMass)
  63. : BasicReplica(newName, newMesh, newEntity, newMass),
  64. havokGameObject(NULL),
  65. m_sHKXFileName(""),
  66. m_eGameObjectType(0),
  67. angularVelocity(Ogre::Vector3::ZERO), realAngularVelocity(Ogre::Vector3::ZERO),
  68. sceneManager(NULL), owningManager(NULL),
  69. useServerPhysicsOnly(false),
  70. currentAnimation("None")
  71. {
  72. }
  73. /// ~GameObjectReplica - Destructor
  74. ///
  75. /// This function also cleans up associated Havok objects and further associated Ogre objects created by said Havok objects.
  76. GameObjectReplica::~GameObjectReplica()
  77. {
  78. // We have to do a little cleanup first before this replica can be destroyed
  79. // properly (because the Havok object doesn't pick up after itself...)
  80. //
  81. // 1. Remove the reference to the havok object from the havok world
  82. // 2. Remove the havok object from the GameObjectManager's list
  83. // 3. Remove the Ogre entity and its parent scene node from the scene.
  84. if(havokGameObject != NULL && owningManager != NULL)
  85. {
  86. owningManager->RemoveGameObject(havokGameObject);
  87. }
  88. else
  89. cout << "[GameObjectReplica/destructor] Could not remove havok information, as there was no valid GameObject or GameObjectManager pointer." << endl;
  90. if(sceneManager != NULL)
  91. {
  92. Ogre::Entity *entity = sceneManager->getEntity(entityName);
  93. if(entity != NULL)
  94. {
  95. Ogre::SceneNode *sceneNode = entity->getParentSceneNode();
  96. if(sceneNode != NULL) sceneManager->destroySceneNode(sceneNode);
  97. sceneManager->destroyEntity(entity);
  98. }
  99. else
  100. {
  101. cout << "[GameObjectReplica/destructor] Could not destroy Ogre scene information, as " << entityName << " could not be found." << endl;
  102. }
  103. }
  104. }
  105. /// GetName - Returns a print out of a name, suitable for framing. Virtual, redefined from GameObjectReplica.
  106. RakNet::RakString
  107. GameObjectReplica::GetName() const
  108. {
  109. Ogre::String ogreString = "Class: GameObjectReplica, Name: ";
  110. ogreString += objName;
  111. return RakNet::RakString(ogreString.c_str());
  112. }
  113. /// WriteAllocationID - Writes a unique string to be used by the replica factory. Virtual, redefined from GameObjectReplica.
  114. ///
  115. /// Parameters:
  116. /// allocationIdBitstream - a RakNet BitStream where the allocation string will be written to (and later read from by the factory)
  117. void
  118. GameObjectReplica::WriteAllocationID(RakNet::Connection_RM3 *destinationConnection, RakNet::BitStream *allocationIdBitstream) const
  119. {
  120. Ogre::String className = "GameObjectReplica";
  121. allocationIdBitstream->Write(className.c_str());
  122. }
  123. /// SerializeConstruction - Serializes data for a remote object reference/creation call.
  124. /// Virtual, redefined from GameObjectReplica.
  125. ///
  126. /// Parameters:
  127. /// constructionBitstream - a RakNet BitStream containing the data to be used in the object's remote construction
  128. /// destinationConnection - the connection the remote object will be created on (in case special serialization is needed)
  129. void
  130. GameObjectReplica::SerializeConstruction(RakNet::BitStream *constructionBitstream, RakNet::Connection_RM3 *destinationConnection)
  131. {
  132. constructionBitstream->Write(GetName() + RakNet::RakString(" SerializeConstruction"));
  133. constructionBitstream->Write(RakNet::RakString(objName.c_str()));
  134. constructionBitstream->Write(RakNet::RakString(meshName.c_str()));
  135. constructionBitstream->Write(RakNet::RakString(m_sHKXFileName.c_str()));
  136. constructionBitstream->Write(mass);
  137. constructionBitstream->Write((int)m_eGameObjectType);
  138. constructionBitstream->Write(position.x);
  139. constructionBitstream->Write(position.y);
  140. constructionBitstream->Write(position.z);
  141. constructionBitstream->Write(orientation.x);
  142. constructionBitstream->Write(orientation.y);
  143. constructionBitstream->Write(orientation.z);
  144. constructionBitstream->Write(orientation.w);
  145. constructionBitstream->Write(velocity.x);
  146. constructionBitstream->Write(velocity.y);
  147. constructionBitstream->Write(velocity.z);
  148. constructionBitstream->Write(angularVelocity.x);
  149. constructionBitstream->Write(angularVelocity.y);
  150. constructionBitstream->Write(angularVelocity.z);
  151. //@Animation
  152. constructionBitstream->Write(RakNet::RakString(currentAnimation.c_str()));
  153. if(topology == SERVER)
  154. {
  155. entityName = objName;
  156. entityName.append(".");
  157. //entityName.append(Ogre::StringConverter::toString((int)GetNetworkID().localSystemAddress));
  158. // raknet 4.0b8
  159. entityName.append(Ogre::StringConverter::toString((int)GetNetworkID()));
  160. }
  161. else
  162. {
  163. }
  164. }
  165. /// DeserializeConstruction - Reads and processes incoming data from a remote object reference/creation call.
  166. /// Virtual, redefined from GameObjectReplica.
  167. ///
  168. /// Parameters:
  169. /// constructionBitstream - a RakNet BitStream containing the data to be used in the object's remote construction
  170. /// sourceConnection - the connection calling for the construction of the object represented by this replica
  171. bool
  172. GameObjectReplica::DeserializeConstruction(RakNet::BitStream *constructionBitstream, RakNet::Connection_RM3 *sourceConnection)
  173. {
  174. RakNet::RakString rakString;
  175. RakNet::RakString rakStringObjectName;
  176. RakNet::RakString rakStringMeshName;
  177. RakNet::RakString rakStringHavokObjectFileName;
  178. RakNet::RakString rakStringHavokObjectModelName;
  179. Ogre::Real initialMass;
  180. int initialHavokObjectType; //initialHavokObjectSubType;
  181. Ogre::Vector3 initialPosition, initialVelocity, initialAngularVelocity;
  182. Ogre::Quaternion initialOrientation;
  183. constructionBitstream->Read(rakString);
  184. constructionBitstream->Read(rakStringObjectName);
  185. constructionBitstream->Read(rakStringMeshName);
  186. constructionBitstream->Read(rakStringHavokObjectFileName);
  187. //constructionBitstream->Read(rakStringHavokObjectModelName);
  188. constructionBitstream->Read(initialMass);
  189. constructionBitstream->Read(initialHavokObjectType);
  190. //constructionBitstream->Read(initialHavokObjectSubType);
  191. constructionBitstream->Read(initialPosition.x);
  192. constructionBitstream->Read(initialPosition.y);
  193. constructionBitstream->Read(initialPosition.z);
  194. constructionBitstream->Read(initialOrientation.x);
  195. constructionBitstream->Read(initialOrientation.y);
  196. constructionBitstream->Read(initialOrientation.z);
  197. constructionBitstream->Read(initialOrientation.w);
  198. constructionBitstream->Read(initialVelocity.x);
  199. constructionBitstream->Read(initialVelocity.y);
  200. constructionBitstream->Read(initialVelocity.z);
  201. constructionBitstream->Read(initialAngularVelocity.x);
  202. constructionBitstream->Read(initialAngularVelocity.y);
  203. constructionBitstream->Read(initialAngularVelocity.z);
  204. //@Animation
  205. RakNet::RakString rakAnimationString;
  206. constructionBitstream->Read(rakAnimationString);
  207. currentAnimation = rakAnimationString.C_String();
  208. objName = rakStringObjectName.C_String();
  209. meshName = rakStringMeshName.C_String();
  210. m_sHKXFileName = rakStringHavokObjectFileName.C_String();
  211. mass = initialMass;
  212. m_eGameObjectType = initialHavokObjectType;
  213. position = realPosition = initialPosition;
  214. orientation = realOrientation = initialOrientation;
  215. velocity = realVelocity = initialVelocity;
  216. angularVelocity = realAngularVelocity = initialAngularVelocity;
  217. if(topology == CLIENT)
  218. {
  219. entityName = objName;
  220. entityName.append(".");
  221. //entityName.append(Ogre::StringConverter::toString((int)GetNetworkID().localSystemAddress));
  222. //raknet 4.0b8
  223. entityName.append(Ogre::StringConverter::toString((int)GetNetworkID()));
  224. }
  225. else
  226. {
  227. }
  228. return true;
  229. }
  230. /// DeallocReplica - Determines what should be done when a replica should be deleted. Virtual, redefined from GameObjectReplica.
  231. ///
  232. /// Parameters:
  233. /// sourceConnection - the connection calling for the destruction of the object represented by this replica
  234. void
  235. GameObjectReplica::DeallocReplica(RakNet::Connection_RM3 *sourceConnection)
  236. {
  237. // RMF deleting the object here consistently causes a crash having to do with m_pGraphicsObject.
  238. //delete this;
  239. }
  240. /// Serialize - Writes data to a Bitstream to be sent to a remote system. Virtual, redefined from GameObjectReplica.
  241. ///
  242. /// If allowed to by the returned result of QuerySerialize, this function runs every call to replicaManager->Update(),
  243. /// for every object, for every connection.
  244. ///
  245. /// Parameters:
  246. /// serializeParameters - a RakNet SerializeParameters class containing the serialized information to be sent
  247. RakNet::RM3SerializationResult
  248. GameObjectReplica::Serialize(RakNet::SerializeParameters *serializeParameters)
  249. {
  250. // If we are a client:
  251. // 1. If this replica is flagged to use server physics, we don't serialize this (might need to move this to QuerySerialize)
  252. // 2. If this object has not been flagged as modified AND it's been less than 1ms since the last update, we don't serialize
  253. // Otherwise, reset the client-modified flag and serialize normally
  254. if(topology1 == CLIENT)
  255. {
  256. if(useServerPhysicsOnly) return RakNet::RM3SR_DO_NOT_SERIALIZE;
  257. /*RakNetTime diffUpdateTime = RakNet::GetTime() - lastUpdateClient;*/
  258. //raknet 4.0b8
  259. RakNet::Time diffUpdateTime = RakNet::GetTime() - lastUpdateClient;
  260. if(!clientModified && ( (RakNet::GetTime() - lastUpdateClient) < 1000) )
  261. {
  262. // cout << "[GameObjectReplica/Serialize] CLIENT: no local modification, should skip serialization this tick" << endl;
  263. return RakNet::RM3SR_DO_NOT_SERIALIZE;
  264. }
  265. else
  266. {
  267. // cout << "[GameObjectReplica/Serialize] CLIENT: locally modified, should serialize to server and reset modification flag" << endl;
  268. clientModified = false;
  269. }
  270. }
  271. /*RakNetTime time = RakNet::GetTime()/1000;*/
  272. //raknet 4.0b8
  273. RakNet::Time time = RakNet::GetTime()/1000;
  274. serializeParameters->outputBitstream[0].Write(time);
  275. serializeParameters->outputBitstream[0].Write(position.x);
  276. serializeParameters->outputBitstream[0].Write(position.y);
  277. serializeParameters->outputBitstream[0].Write(position.z);
  278. serializeParameters->outputBitstream[0].Write(realPosition.x);
  279. serializeParameters->outputBitstream[0].Write(realPosition.y);
  280. serializeParameters->outputBitstream[0].Write(realPosition.z);
  281. serializeParameters->outputBitstream[0].Write(orientation.x);
  282. serializeParameters->outputBitstream[0].Write(orientation.y);
  283. serializeParameters->outputBitstream[0].Write(orientation.z);
  284. serializeParameters->outputBitstream[0].Write(orientation.w);
  285. serializeParameters->outputBitstream[0].Write(realOrientation.x);
  286. serializeParameters->outputBitstream[0].Write(realOrientation.y);
  287. serializeParameters->outputBitstream[0].Write(realOrientation.z);
  288. serializeParameters->outputBitstream[0].Write(realOrientation.w);
  289. serializeParameters->outputBitstream[0].Write(velocity.x);
  290. serializeParameters->outputBitstream[0].Write(velocity.y);
  291. serializeParameters->outputBitstream[0].Write(velocity.z);
  292. serializeParameters->outputBitstream[0].Write(realVelocity.x);
  293. serializeParameters->outputBitstream[0].Write(realVelocity.y);
  294. serializeParameters->outputBitstream[0].Write(realVelocity.z);
  295. serializeParameters->outputBitstream[0].Write(angularVelocity.x);
  296. serializeParameters->outputBitstream[0].Write(angularVelocity.y);
  297. serializeParameters->outputBitstream[0].Write(angularVelocity.z);
  298. serializeParameters->outputBitstream[0].Write(realAngularVelocity.x);
  299. serializeParameters->outputBitstream[0].Write(realAngularVelocity.y);
  300. serializeParameters->outputBitstream[0].Write(realAngularVelocity.z);
  301. //@Animation
  302. //Note entering here since no string entered here
  303. serializeParameters->outputBitstream[0].Write(RakNet::RakString(currentAnimation.c_str()));
  304. // set a non-zero value so the timestamp is passed
  305. serializeParameters->messageTimestamp = RakNet::GetTime();
  306. // update the appropriate timestamp for the source of this update (can be used later for interpolation)
  307. if(topology == CLIENT)
  308. lastUpdateClient = RakNet::GetTime();
  309. else
  310. lastUpdateServer = RakNet::GetTime();
  311. return RakNet::RM3SR_BROADCAST_IDENTICALLY;
  312. }
  313. /// Deserialize - Reads and processes incoming data from a remote serialization.
  314. /// Virtual, redefined from GameObjectReplica.
  315. ///
  316. /// Parameters:
  317. /// deserializeParameters - a RakNet DeserializeParameters class containing the serialized information to be read
  318. void
  319. GameObjectReplica::Deserialize(RakNet::DeserializeParameters *deserializeParameters)
  320. {
  321. //RakNetTime dsTime;
  322. //raknet 4.0b8
  323. RakNet::Time dsTime;
  324. Ogre::Vector3 newPosition, newRealPosition;
  325. Ogre::Quaternion newOrientation, newRealOrientation;
  326. Ogre::Vector3 newVelocity, newRealVelocity;
  327. Ogre::Vector3 newAngularVelocity, newRealAngularVelocity;
  328. // Read in the values from the serialization string here. The order has to match the original serialization order.
  329. deserializeParameters->serializationBitstream[0].Read(dsTime);
  330. deserializeParameters->serializationBitstream[0].Read(newPosition.x);
  331. deserializeParameters->serializationBitstream[0].Read(newPosition.y);
  332. deserializeParameters->serializationBitstream[0].Read(newPosition.z);
  333. deserializeParameters->serializationBitstream[0].Read(newRealPosition.x);
  334. deserializeParameters->serializationBitstream[0].Read(newRealPosition.y);
  335. deserializeParameters->serializationBitstream[0].Read(newRealPosition.z);
  336. deserializeParameters->serializationBitstream[0].Read(newOrientation.x);
  337. deserializeParameters->serializationBitstream[0].Read(newOrientation.y);
  338. deserializeParameters->serializationBitstream[0].Read(newOrientation.z);
  339. deserializeParameters->serializationBitstream[0].Read(newOrientation.w);
  340. deserializeParameters->serializationBitstream[0].Read(newRealOrientation.x);
  341. deserializeParameters->serializationBitstream[0].Read(newRealOrientation.y);
  342. deserializeParameters->serializationBitstream[0].Read(newRealOrientation.z);
  343. deserializeParameters->serializationBitstream[0].Read(newRealOrientation.w);
  344. deserializeParameters->serializationBitstream[0].Read(newVelocity.x);
  345. deserializeParameters->serializationBitstream[0].Read(newVelocity.y);
  346. deserializeParameters->serializationBitstream[0].Read(newVelocity.z);
  347. deserializeParameters->serializationBitstream[0].Read(newRealVelocity.x);
  348. deserializeParameters->serializationBitstream[0].Read(newRealVelocity.y);
  349. deserializeParameters->serializationBitstream[0].Read(newRealVelocity.z);
  350. deserializeParameters->serializationBitstream[0].Read(newAngularVelocity.x);
  351. deserializeParameters->serializationBitstream[0].Read(newAngularVelocity.y);
  352. deserializeParameters->serializationBitstream[0].Read(newAngularVelocity.z);
  353. deserializeParameters->serializationBitstream[0].Read(newRealAngularVelocity.x);
  354. deserializeParameters->serializationBitstream[0].Read(newRealAngularVelocity.y);
  355. deserializeParameters->serializationBitstream[0].Read(newRealAngularVelocity.z);
  356. //@Animation
  357. RakNet::RakString rakAnimationString;
  358. deserializeParameters->serializationBitstream[0].Read(rakAnimationString);
  359. currentAnimation = rakAnimationString.C_String();
  360. // Now that we have all of the serialized values from the update, we have to determine what to do with them.
  361. // If we are the server:
  362. // 1. Set the last client update time (this can be used later for extrapolation)
  363. // 2. Check the values for validity. There's no real checking done below, and so we accept the values as valid by default
  364. // If the value(s) are valid:
  365. // 1. Set the "local" and the server-side values to the client-requested values
  366. // 2. Update the rigid body information with this new update so it can be processed by the Havok world later
  367. if(topology == SERVER)
  368. {
  369. lastUpdateClient = RakNet::GetTime();
  370. if(true) // sanity check the position update sent from the client
  371. {
  372. position = realPosition = newPosition;
  373. orientation = realOrientation = newOrientation;
  374. velocity = realVelocity = newVelocity;
  375. angularVelocity = realAngularVelocity = newAngularVelocity;
  376. if(havokGameObject != NULL) SetHavokRigidBodyInfo(position, orientation, velocity, angularVelocity);
  377. }
  378. else
  379. serverCorrected = true;
  380. }
  381. else
  382. {
  383. // Otherwise, this is a client:
  384. // 1. Set the last server update time (this can be used later for extrapolation)
  385. // 2. If the update from the server is different than the last update (the values currently stored in the real* variables):
  386. // If this object is a keyframed object, we only copy the position and orientation values.
  387. // Otherwise, this is a normal object and:
  388. // 1. Update the server values with the latest values from the server
  389. // 2. Update the client-side positions only if the server update is outside of a specific range, or we don't own this object
  390. lastUpdateServer = RakNet::GetTime();
  391. if(realPosition != newRealPosition || realOrientation != newRealOrientation || velocity != newRealVelocity || angularVelocity != newAngularVelocity)
  392. {
  393. if(m_eGameObjectType == PHYSICS_KEYFRAMED)
  394. {
  395. position = realPosition = newPosition;
  396. orientation = realOrientation = newOrientation;
  397. velocity = realVelocity = Ogre::Vector3::ZERO;
  398. angularVelocity = realAngularVelocity = Ogre::Vector3::ZERO;
  399. }
  400. else
  401. {
  402. realPosition = newRealPosition;
  403. realOrientation = newRealOrientation;
  404. realVelocity = newRealVelocity;
  405. realAngularVelocity = newRealAngularVelocity;
  406. if(position.squaredDistance(realPosition) > 1 || !orientation.equals(realOrientation, Ogre::Radian((Ogre::Real)0.1475)) ||
  407. //creatingSystemGUID != replicaManager->GetRakPeerInterface()->GetGuidFromSystemAddress(UNASSIGNED_SYSTEM_ADDRESS))
  408. //raknet 4.0b8
  409. creatingSystemGUID != replicaManager->GetRakPeerInterface()->GetGuidFromSystemAddress(RakNet::UNASSIGNED_SYSTEM_ADDRESS))
  410. {
  411. // This section would probably be better done by using lerp for position and slerp for orientation instead of direct copy
  412. position = realPosition;
  413. orientation = realOrientation;
  414. velocity = realVelocity;
  415. angularVelocity = realAngularVelocity;
  416. }
  417. }
  418. // update the rigid body information with the correctly updated information
  419. if(havokGameObject != NULL) SetHavokRigidBodyInfo(position, orientation, velocity, angularVelocity);
  420. // flag to indicate this was corrected by the server, might be vestigial now
  421. serverCorrected = true;
  422. }
  423. }
  424. }
  425. /* Havok-related functions */
  426. /// GetHavokGameObject - Sets a pointer to the Havok GameObject associated with this replica
  427. void GameObjectReplica::SetHavokGameObject(GameObject *newHavokGameObject) {havokGameObject = newHavokGameObject; }
  428. /// GetHavokObjectFileName - Sets the filename where the object's Havok information is stored (eg., "object.hkx")
  429. void GameObjectReplica::SetHavokObjectFileName(const char *newHavokObjectFileName) { m_sHKXFileName = newHavokObjectFileName; }
  430. void
  431. GameObjectReplica::SetHavokObjectFileInfo(const char *newHavokObjectFileName, const char *newMeshName)
  432. {
  433. SetHavokObjectFileName(newHavokObjectFileName);
  434. SetMeshName(newMeshName);
  435. }
  436. /// SetHavokObjectType - Sets an object's primary Havok type (GameObjectType)
  437. void GameObjectReplica::SetHavokObjectType(int newHavokObjectType) { m_eGameObjectType = newHavokObjectType; }
  438. /// SetAngularVelocity - Sets the local value for an object's angular velocity. Uses 3 floats.
  439. void GameObjectReplica::SetAngularVelocity(float x, float y, float z) { angularVelocity = Ogre::Vector3(x, y, z); }
  440. /// SetAngularVelocity - Sets the local value for an object's angular velocity. Uses a Vector3.
  441. void GameObjectReplica::SetAngularVelocity(Ogre::Vector3 newAngularVelocity) { angularVelocity = newAngularVelocity; }
  442. /// SetRealAngularVelocity - Sets the server's last updated value for an object's angular velocity. Uses 3 floats.
  443. void GameObjectReplica::SetRealAngularVelocity(float x, float y, float z) { realAngularVelocity = Ogre::Vector3(x, y, z); }
  444. /// SetRealAngularVelocity - Sets the server's last updated value for an object's angular velocity. Uses a Vector3.
  445. void GameObjectReplica::SetRealAngularVelocity(Ogre::Vector3 newRealAngularVelocity) { realAngularVelocity = newRealAngularVelocity; }
  446. /// GetHavokGameObject - Gets a pointer to the Havok GameObject associated with this replica
  447. GameObject * GameObjectReplica::GetHavokGameObject() { return havokGameObject; }
  448. /// GetHavokObjectFileName - Gets the filename where the object's Havok information is stored (eg., "object.hkx")
  449. Ogre::String GameObjectReplica::GetHavokObjectFileName() { return m_sHKXFileName; }
  450. /// GetHavokObjectType - Gets an object's primary Havok type (GameObjectType)
  451. GameObjectType GameObjectReplica::GetHavokObjectType() { return static_cast<GameObjectType>(m_eGameObjectType); }
  452. /// GetAngularVelocity - Gets the local value for an object's angular velocity.
  453. Ogre::Vector3 GameObjectReplica::GetAngularVelocity() { return angularVelocity; }
  454. /// GetRealAngularVelocity - Gets the server's last updated value for an object's angular velocity.
  455. Ogre::Vector3 GameObjectReplica::GetRealAngularVelocity() { return realAngularVelocity; }
  456. /// GetHavokRigidBodyInfo - Copies spatial and physics information from a Havok GameObject
  457. ///
  458. /// This function accounts for the different Havok object types.
  459. ///
  460. /// Parameters:
  461. /// hkPosition - a reference to a Havok position vector
  462. /// hkVelocity - a reference to a Havok velocity vector
  463. /// hkAngularVelocity - a reference to a Havok angular velocity vector
  464. /// hkOrientation - a reference to a Havok orientation quaternion
  465. void
  466. GameObjectReplica::GetHavokRigidBodyInfo(hkVector4 &hkPosition, hkVector4 &hkVelocity, hkVector4 &hkAngularVelocity, hkQuaternion &hkOrientation)
  467. {
  468. hkPosition.set(0, 0, 0);
  469. hkVelocity.set(0, 0, 0);
  470. hkAngularVelocity.set(0, 0, 0);
  471. hkOrientation.m_vec.set(0, 0, 0, 1);
  472. // The raw spatial information is available through different sources depending on the Havok object type
  473. // Here we have to differentiate between the following Havok types:
  474. // 1. {CHARACTER, CHARACTER_RIGIDBODY) - information is available through the CharacterRigidBodyObject->hkpRigidBody pointer
  475. // 2. {CHARACTER, CHARACTER_PROXY} - only position and velocity information is available, orientation/angular velocity not supported
  476. // 3. {PHYSICS, *} - information is available through the PhysicsObject->hkpRigidBody pointer
  477. if ((havokGameObject->m_eObjectType == ANIMATED_CHARACTER_RIGIDBODY)||(havokGameObject->m_eObjectType == PHYSICS_CHARACTER_RIGIDBODY))
  478. {
  479. CharacterRigidBodyObject *crbo = static_cast<CharacterRigidBodyObject *>(havokGameObject->m_pPhysicsObject);
  480. hkPosition = crbo->getCharacterRigidBody()->getRigidBody()->getPosition();
  481. hkVelocity = crbo->getCharacterRigidBody()->getRigidBody()->getLinearVelocity();
  482. hkAngularVelocity = crbo->getCharacterRigidBody()->getRigidBody()->getAngularVelocity();
  483. hkOrientation = crbo->getCharacterRigidBody()->getRigidBody()->getRotation();
  484. }
  485. else if((havokGameObject->m_eObjectType == ANIMATED_CHARACTER_PROXY)||(havokGameObject->m_eObjectType == PHYSICS_CHARACTER_PROXY))
  486. {
  487. CharacterProxyObject *cpo = static_cast<CharacterProxyObject *>(havokGameObject->m_pPhysicsObject);
  488. hkPosition = cpo->getCharacterProxy()->getPosition();
  489. hkVelocity = cpo->getCharacterProxy()->getLinearVelocity();
  490. }
  491. else
  492. {
  493. Ogre::Vector3 gameObjectPosition = havokGameObject->getPosition();
  494. hkPosition = hkVector4(gameObjectPosition.x,gameObjectPosition.y,gameObjectPosition.z);
  495. PhysicsPrimitiveObject* f_pTempObject = (PhysicsPrimitiveObject*)havokGameObject->m_pPhysicsObject;
  496. if (f_pTempObject!=NULL)
  497. {
  498. hkOrientation = f_pTempObject->getRigidBody()->getRotation();
  499. hkVelocity = f_pTempObject->getRigidBody()->getLinearVelocity();
  500. hkAngularVelocity = f_pTempObject->getRigidBody()->getAngularVelocity();
  501. }
  502. else//this should be fixed, functions should be added to PhysicsObject and all children under it
  503. { hkOrientation = hkQuaternion(0,0,0,1);
  504. hkVelocity = hkVector4(0,0,0);
  505. hkAngularVelocity = hkVector4(0,0,0);
  506. }
  507. }
  508. }
  509. /// SetHavokRigidBodyInfo - Copies spatial and physics information into a Havok GameObject
  510. ///
  511. /// This function converts Ogre data types to Havok data types and accounts for the different Havok object types.
  512. ///
  513. /// Parameters:
  514. /// updatePosition - a new position vector
  515. /// updateOrientation - a new orientation quaternion
  516. /// updateVelocity - a new velocity vector
  517. /// updateAngularVelocity - a new angular velocity vector
  518. void
  519. GameObjectReplica::SetHavokRigidBodyInfo(Ogre::Vector3 updatePosition, Ogre::Quaternion updateOrientation, Ogre::Vector3 updateVelocity, Ogre::Vector3 updateAngularVelocity)
  520. {
  521. hkVector4 newPosition, newVelocity, newAngularVelocity;
  522. hkQuaternion newOrientation;
  523. newPosition.set(updatePosition.x, updatePosition.y, updatePosition.z);
  524. newVelocity.set(updateVelocity.x, updateVelocity.y, updateVelocity.z);
  525. newAngularVelocity.set(updateAngularVelocity.x, updateAngularVelocity.y, updateAngularVelocity.z);
  526. newOrientation.m_vec.set(updateOrientation.x, updateOrientation.y, updateOrientation.z, updateOrientation.w);
  527. if((havokGameObject->m_eObjectType == ANIMATED_CHARACTER_RIGIDBODY)||(havokGameObject->m_eObjectType == PHYSICS_CHARACTER_RIGIDBODY))
  528. {
  529. CharacterRigidBodyObject *crbo = dynamic_cast<CharacterRigidBodyObject *>(havokGameObject->m_pPhysicsObject);
  530. crbo->getCharacterRigidBody()->getRigidBody()->setPosition(newPosition);
  531. crbo->getCharacterRigidBody()->getRigidBody()->setRotation(newOrientation);
  532. crbo->getCharacterRigidBody()->getRigidBody()->setLinearVelocity(newVelocity);
  533. crbo->getCharacterRigidBody()->getRigidBody()->setAngularVelocity(newAngularVelocity);
  534. }
  535. else if((havokGameObject->m_eObjectType == ANIMATED_CHARACTER_PROXY)||(havokGameObject->m_eObjectType == PHYSICS_CHARACTER_PROXY))
  536. {
  537. CharacterProxyObject *cpo = static_cast<CharacterProxyObject *>(havokGameObject->m_pPhysicsObject);
  538. cpo->getCharacterProxy()->setPosition(newPosition);
  539. cpo->getCharacterProxy()->setLinearVelocity(newVelocity);
  540. }
  541. else
  542. {
  543. havokGameObject->setPosition(updatePosition.x,updatePosition.y,updatePosition.z);
  544. PhysicsPrimitiveObject* f_pTempObject = (PhysicsPrimitiveObject*)havokGameObject->m_pPhysicsObject;
  545. if (f_pTempObject!=NULL)
  546. {
  547. f_pTempObject->getRigidBody()->setRotation(newOrientation);
  548. f_pTempObject->getRigidBody()->setLinearVelocity(newVelocity);
  549. f_pTempObject->getRigidBody()->setAngularVelocity(newAngularVelocity);
  550. }
  551. else
  552. {
  553. //do we need to set these parameters unless the object is physics primitive??
  554. //this should be fixed, functions should be added to PhysicsObject and all children under it
  555. }
  556. }
  557. }
  558. /// playAnimation - Play animation on GameObject for this replica
  559. /// Parameters: animationName - Name of animation to be played
  560. ///
  561. /// Returns: Nothing.
  562. void GameObjectReplica::playAnimation(Ogre::String animationName)
  563. {
  564. if(havokGameObject==NULL)
  565. {
  566. //try finding
  567. Ogre::String objectName = GetObjectName();
  568. Ogre::String newEntityName = objectName + ".";
  569. newEntityName.append(Ogre::StringConverter::toString((int)(GetNetworkID())));
  570. GameObject *hgameobject = GetGameObjectManager()->GetGameObject(newEntityName);
  571. if(hgameobject==NULL)
  572. return;
  573. else
  574. havokGameObject = hgameobject;
  575. }
  576. if(hasAnimation(animationName))
  577. {
  578. havokGameObject->m_pAnimatedEntity->StopAnimation();
  579. havokGameObject->PlayAnimation(animationName);
  580. currentAnimation = animationName;
  581. return;
  582. }
  583. else
  584. {
  585. currentAnimation="None";
  586. stopAnimation();
  587. }
  588. }
  589. /// stopAnimation - Stop animation on GameObject for this replica. If no name is specified, stops all animations
  590. /// Parameters: animationName - Name of animation to be stopeed
  591. ///
  592. /// Returns: Nothing.
  593. void GameObjectReplica::stopAnimation(Ogre::String animationName)
  594. {
  595. if(havokGameObject==NULL)
  596. {
  597. //try finding
  598. Ogre::String objectName = GetObjectName();
  599. Ogre::String newEntityName = objectName + ".";
  600. newEntityName.append(Ogre::StringConverter::toString((int)(GetNetworkID())));
  601. GameObject *hgameobject = GetGameObjectManager()->GetGameObject(newEntityName);
  602. if(hgameobject==NULL)
  603. return;
  604. else
  605. havokGameObject = hgameobject;
  606. }
  607. if(animationName=="")
  608. {
  609. currentAnimation="None";
  610. havokGameObject->m_pAnimatedEntity->StopAnimation();
  611. }
  612. else if(currentAnimation==animationName)
  613. {
  614. currentAnimation="None";
  615. havokGameObject->m_pAnimatedEntity->StopAnimation();
  616. }
  617. else
  618. return;
  619. }
  620. /// hasAnimation - Returns whether or not replica has an animation or not
  621. /// Parameters: animationName - Name of animation to be queried
  622. ///
  623. /// Returns: bool depending on animation found or not
  624. bool GameObjectReplica::hasAnimation(Ogre::String animationName)
  625. {
  626. if(havokGameObject==NULL)
  627. {
  628. //try finding
  629. Ogre::String objectName = GetObjectName();
  630. Ogre::String newEntityName = objectName + ".";
  631. newEntityName.append(Ogre::StringConverter::toString((int)(GetNetworkID())));
  632. GameObject *hgameobject = GetGameObjectManager()->GetGameObject(newEntityName);
  633. if(hgameobject==NULL)
  634. return false;
  635. else
  636. havokGameObject = hgameobject;
  637. }
  638. if(havokGameObject->HasAnimationName(animationName))
  639. return true;
  640. return false;
  641. }
  642. /// ProcessHavokStep - Processes an object after a previous Havok world simulation step.
  643. ///
  644. /// Using this information, a server can determine whether it should send out an update for an object it's responsible for.
  645. /// A client will be able to use this function to determine whether it should send its own update, or rollback changes made
  646. /// by its local physics world.
  647. ///
  648. /// Parameters: isOwner - a flag indicating whether the GUID of the system creating the replica matches the GUID of this system
  649. ///
  650. /// Returns: Nothing. A call to this function when a Havok GameObject does not exist will simply return.
  651. void
  652. GameObjectReplica::ProcessHavokStep(bool isOwner,NetTopology topology)
  653. {
  654. // If there's no associated Havok GameObject, then there's no point in updating.
  655. if(havokGameObject == NULL) return;
  656. AnimationManager::AnimatedEntity *animatedEntity = havokGameObject->m_pAnimatedEntity;
  657. if(animatedEntity!=NULL)
  658. {
  659. if(topology == SERVER)
  660. {
  661. // isanimationplaying not working with havok animation so cant use server update
  662. }
  663. else
  664. {
  665. if(currentAnimation=="None")
  666. {
  667. animatedEntity->StopAnimation();
  668. }
  669. else if(animatedEntity->HasAnimationName(currentAnimation) && currentAnimation!=animatedEntity->GetActiveAnimation())
  670. {
  671. if((m_sHKXFileName=="" && !animatedEntity->IsAnimationPlaying(currentAnimation.c_str())))
  672. havokGameObject->PlayAnimation(currentAnimation);
  673. else if(m_sHKXFileName.length() > 0)
  674. {
  675. animatedEntity->StopAnimation();
  676. havokGameObject->PlayAnimation(currentAnimation);
  677. }
  678. }
  679. else if(animatedEntity->HasAnimationName(currentAnimation))
  680. {
  681. //do nothing
  682. }
  683. else
  684. {
  685. animatedEntity->StopAnimation();
  686. }
  687. }
  688. }
  689. if(havokGameObject->m_eObjectType==GRAPHICS_OBJECT)
  690. {
  691. velocity = realVelocity = Ogre::Vector3(0,0,0);
  692. angularVelocity = realAngularVelocity = Ogre::Vector3(0,0,0);
  693. if(topology == SERVER)
  694. {
  695. position = realPosition = havokGameObject->getPosition();
  696. serverCorrected = true;
  697. }
  698. else
  699. {
  700. if(useServerPhysicsOnly)
  701. {
  702. position = realPosition;
  703. havokGameObject->setPosition(realPosition.x,realPosition.y,realPosition.z);
  704. }
  705. else
  706. {
  707. clientModified = true;
  708. }
  709. }
  710. return;
  711. }
  712. // Now that the simulation has taken a step, we update the "real" values. If the "real" value is different
  713. // than the previous value, it has been effectively modified and and it should be serialized to the server/client
  714. hkVector4 postHavokPosition, postHavokVelocity, postHavokAngularVelocity;
  715. hkQuaternion postHavokOrientation;
  716. if(havokGameObject->m_eObjectType!=GRAPHICS_OBJECT)
  717. GetHavokRigidBodyInfo(postHavokPosition, postHavokVelocity, postHavokAngularVelocity, postHavokOrientation);
  718. // For readability, I'm converting the Havok types to Ogre types
  719. Ogre::Vector3 postHavokPositionV3 = Ogre::Vector3(postHavokPosition.getQuad().v[0], postHavokPosition.getQuad().v[1], postHavokPosition.getQuad().v[2]);
  720. Ogre::Vector3 postHavokVelocityV3 = Ogre::Vector3(postHavokVelocity.getQuad().v[0], postHavokVelocity.getQuad().v[1], postHavokVelocity.getQuad().v[2]);
  721. Ogre::Vector3 postHavokAngularVelocityV3 = Ogre::Vector3(postHavokAngularVelocity.getQuad().v[0], postHavokAngularVelocity.getQuad().v[1], postHavokAngularVelocity.getQuad().v[2]);
  722. Ogre::Quaternion postHavokOrientationQ = Ogre::Quaternion(postHavokOrientation.m_vec.getQuad().v[3], postHavokOrientation.m_vec.getQuad().v[0], postHavokOrientation.m_vec.getQuad().v[1], postHavokOrientation.m_vec.getQuad().v[2]);
  723. // If this is the server, it is the authority on objects' spatial properties. Thus, we have to:
  724. // 1. Update the "real" (server-side) positions with the new values obtained from the havok objects' rigid bodies
  725. // 2. Update the current positions with the new values
  726. // 3. If this object is owned by the server, then we automatically flag it as server-corrected
  727. // Otherwise, we only flag the object as server-corrected if the new spatial information is outside a certain bounds
  728. if(topology == SERVER)
  729. {
  730. realPosition = postHavokPositionV3;
  731. realVelocity = postHavokVelocityV3;
  732. realAngularVelocity = postHavokAngularVelocityV3;
  733. realOrientation = postHavokOrientationQ;
  734. // If this object is owned by us (the server), then we set the "client" values and mark it as server-corrected.
  735. if(isOwner)
  736. {
  737. position = postHavokPositionV3;
  738. velocity = postHavokVelocityV3;
  739. angularVelocity = postHavokAngularVelocityV3;
  740. orientation = postHavokOrientationQ;
  741. serverCorrected = true;
  742. }
  743. else
  744. {
  745. // Otherwise, this object is "owned" by a client and we only want to send an update if the new
  746. // spatial information is out of a certain bounds. If it is, correct the "client" information and mark it
  747. // as server-corrected.
  748. if(HavokObjectUpdateTest(position, postHavokPositionV3, velocity, postHavokVelocityV3, angularVelocity, postHavokAngularVelocityV3,
  749. orientation, postHavokOrientationQ, Ogre::Real(1), Ogre::Radian(Ogre::Degree(1))))
  750. {
  751. position = postHavokPositionV3;
  752. velocity = postHavokVelocityV3;
  753. angularVelocity = postHavokAngularVelocityV3;
  754. orientation = postHavokOrientationQ;
  755. serverCorrected = true;
  756. }
  757. }
  758. }
  759. else
  760. {
  761. // This is the client, where we are the authority on only the objects we create on the client.
  762. // 1. Store the old, pre-Havok-step information
  763. // 2. If the object is flagged to use server physics only, we reverse the Havok update by restoring the old values
  764. // 3. If the object is not a keyframed object, then update the current (client-side) information with the Havok update
  765. // Otherwise (for keyframed objects), we set the "real" spatial information to match the previous update
  766. // This is a fix that prevents keyframed objects from spazzing out because of the local Havok step
  767. // This *should* be ok, because the server maintains these objects' motion anyway
  768. // 4. Mark only the replicas that have moved substantially as client-modified
  769. // Reset values to the last server update if this object is flagged to use the server's physics only.
  770. // Also, do this for keyframed objects, as the server will determine its position and orientation information
  771. Ogre::Vector3 oldClientPosition = position;
  772. Ogre::Quaternion oldClientOrientation = orientation;
  773. Ogre::Vector3 oldClientVelocity = velocity;
  774. Ogre::Vector3 oldClientAngularVelocity = angularVelocity;
  775. if(useServerPhysicsOnly || m_eGameObjectType == PHYSICS_KEYFRAMED)
  776. {
  777. clientModified = false;
  778. position = realPosition;
  779. orientation = realOrientation;
  780. velocity = realVelocity;
  781. angularVelocity = realAngularVelocity;
  782. //raknet 4.0b8
  783. //realPosition = postHavokPositionV3;
  784. SetHavokRigidBodyInfo(realPosition, realOrientation, realVelocity, realAngularVelocity);
  785. return;
  786. }
  787. // Set the client-side information with the post-Havok-step values...
  788. position = postHavokPositionV3;
  789. velocity = postHavokVelocityV3;
  790. angularVelocity = postHavokAngularVelocityV3;
  791. orientation = postHavokOrientationQ;
  792. // Flag the object as client-modified if there was a change beyond a certain spatial bounds.
  793. if(HavokObjectUpdateTest(postHavokPositionV3, oldClientPosition, postHavokVelocityV3, oldClientVelocity,
  794. postHavokAngularVelocityV3, oldClientAngularVelocity, postHavokOrientationQ, oldClientOrientation,
  795. Ogre::Real(1), Ogre::Radian(Ogre::Degree(1))))
  796. {
  797. clientModified = true;
  798. }
  799. }
  800. }
  801. /// SetSceneManager - Sets a pointer to the Ogre scene manager the Havok object is being rendered in.
  802. void GameObjectReplica::SetSceneManager(Ogre::SceneManager *newSceneManager) { sceneManager = newSceneManager; }
  803. /// SetGameObjectManager - Sets a pointer to the Havok GameObjectManager the Havok object will be stored in.
  804. void GameObjectReplica::SetGameObjectManager(GameObjectManager *newManager) { owningManager = newManager; }
  805. /// SetUseServerPhysicsOnly - Sets a flag indicating whether the local physics updates for an object should be ignored.
  806. void GameObjectReplica::SetUseServerPhysicsOnly(bool newUSPO) { useServerPhysicsOnly = newUSPO; }
  807. /// GetSceneManager - Gets a pointer to the Ogre scene manager the Havok object is rendered in. Can be NULL.
  808. Ogre::SceneManager * GameObjectReplica::GetSceneManager() { return sceneManager; }
  809. /// GetGameObjectManager - Gets a pointer to the GameObjectManager the Havok object is stored in. Can be NULL.
  810. GameObjectManager * GameObjectReplica::GetGameObjectManager() { return owningManager; }
  811. /// GetSceneManager - Gets a flag indicating whether the object should use only physics updates from the server.
  812. bool GameObjectReplica::GetUseServerPhysicsOnly() { return useServerPhysicsOnly; }
  813. } // end namespace GamePipeGame
  814. #endif