netObject.cc 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "sim/simBase.h"
  24. #include "network/connectionProtocol.h"
  25. #include "network/netConnection.h"
  26. #include "network/netObject.h"
  27. #include "console/consoleTypes.h"
  28. IMPLEMENT_CONOBJECT(NetObject);
  29. //----------------------------------------------------------------------------
  30. NetObject *NetObject::mDirtyList = NULL;
  31. NetObject::NetObject()
  32. {
  33. // netFlags will clear itself to 0
  34. mNetIndex = U32(-1);
  35. mFirstObjectRef = NULL;
  36. mPrevDirtyList = NULL;
  37. mNextDirtyList = NULL;
  38. mDirtyMaskBits = 0;
  39. }
  40. NetObject::~NetObject()
  41. {
  42. if(mDirtyMaskBits)
  43. {
  44. if(mPrevDirtyList)
  45. mPrevDirtyList->mNextDirtyList = mNextDirtyList;
  46. else
  47. mDirtyList = mNextDirtyList;
  48. if(mNextDirtyList)
  49. mNextDirtyList->mPrevDirtyList = mPrevDirtyList;
  50. }
  51. }
  52. void NetObject::setMaskBits(U32 orMask)
  53. {
  54. AssertFatal(orMask != 0, "Invalid net mask bits set.");
  55. AssertFatal(mDirtyMaskBits == 0 || (mPrevDirtyList != NULL || mNextDirtyList != NULL || mDirtyList == this), "Invalid dirty list state.");
  56. if(!mDirtyMaskBits)
  57. {
  58. AssertFatal(mNextDirtyList == NULL && mPrevDirtyList == NULL, "Object with zero mask already in list.");
  59. if(mDirtyList)
  60. {
  61. mNextDirtyList = mDirtyList;
  62. mDirtyList->mPrevDirtyList = this;
  63. }
  64. mDirtyList = this;
  65. }
  66. mDirtyMaskBits |= orMask;
  67. AssertFatal(mDirtyMaskBits == 0 || (mPrevDirtyList != NULL || mNextDirtyList != NULL || mDirtyList == this), "Invalid dirty list state.");
  68. }
  69. void NetObject::clearMaskBits(U32 orMask)
  70. {
  71. if(isDeleted())
  72. return;
  73. if(mDirtyMaskBits)
  74. {
  75. mDirtyMaskBits &= ~orMask;
  76. if(!mDirtyMaskBits)
  77. {
  78. if(mPrevDirtyList)
  79. mPrevDirtyList->mNextDirtyList = mNextDirtyList;
  80. else
  81. mDirtyList = mNextDirtyList;
  82. if(mNextDirtyList)
  83. mNextDirtyList->mPrevDirtyList = mPrevDirtyList;
  84. mNextDirtyList = mPrevDirtyList = NULL;
  85. }
  86. }
  87. for(GhostInfo *walk = mFirstObjectRef; walk; walk = walk->nextObjectRef)
  88. {
  89. if(walk->updateMask && walk->updateMask == orMask)
  90. {
  91. walk->updateMask = 0;
  92. walk->connection->ghostPushToZero(walk);
  93. }
  94. else
  95. walk->updateMask &= ~orMask;
  96. }
  97. }
  98. void NetObject::collapseDirtyList()
  99. {
  100. Vector<NetObject *> tempV;
  101. for(NetObject *t = mDirtyList; t; t = t->mNextDirtyList)
  102. tempV.push_back(t);
  103. for(NetObject *obj = mDirtyList; obj; )
  104. {
  105. NetObject *next = obj->mNextDirtyList;
  106. U32 orMask = obj->mDirtyMaskBits;
  107. obj->mNextDirtyList = NULL;
  108. obj->mPrevDirtyList = NULL;
  109. obj->mDirtyMaskBits = 0;
  110. if(!obj->isDeleted() && orMask)
  111. {
  112. for(GhostInfo *walk = obj->mFirstObjectRef; walk; walk = walk->nextObjectRef)
  113. {
  114. if(!walk->updateMask)
  115. {
  116. walk->updateMask = orMask;
  117. walk->connection->ghostPushNonZero(walk);
  118. }
  119. else
  120. walk->updateMask |= orMask;
  121. }
  122. }
  123. obj = next;
  124. }
  125. mDirtyList = NULL;
  126. for(U32 i = 0; i < (U32)tempV.size(); i++)
  127. {
  128. AssertFatal(tempV[i]->mNextDirtyList == NULL && tempV[i]->mPrevDirtyList == NULL && tempV[i]->mDirtyMaskBits == 0, "Error in collapse");
  129. }
  130. }
  131. //-----------------------------------------------------------------------------
  132. ConsoleMethod(NetObject,scopeToClient,void,3,3,"( client ) Use the scopeToClient method to force this object to be SCOPE_ALWAYS on client.\n"
  133. "When an object is SCOPE_ALWAYS it is always ghosted. Therefore, if you have an object that should always be ghosted to a client, use this method.\n"
  134. "@param client The ID of the client to force this object to be SCOPE_ALWAYS for.\n"
  135. "@return No return value.\n"
  136. "@sa clearScopeToClient, setScopeAlways")
  137. {
  138. NetConnection *conn;
  139. if(!Sim::findObject(argv[2], conn))
  140. {
  141. Con::errorf(ConsoleLogEntry::General, "NetObject::scopeToClient: Couldn't find connection %s", argv[2]);
  142. return;
  143. }
  144. conn->objectLocalScopeAlways(object);
  145. }
  146. ConsoleMethod(NetObject,clearScopeToClient,void,3,3,"( client ) Use the clearScopeToClient method to undo the effects of a previous call to scopeToClient.\n"
  147. "@param client The ID of the client to stop forcing scoping this object for.\n"
  148. "@return No return value.\n"
  149. "@sa scopeToClient")
  150. {
  151. NetConnection *conn;
  152. if(!Sim::findObject(argv[2], conn))
  153. {
  154. Con::errorf(ConsoleLogEntry::General, "NetObject::clearScopeToClient: Couldn't find connection %s", argv[2]);
  155. return;
  156. }
  157. conn->objectLocalClearAlways(object);
  158. }
  159. ConsoleMethod(NetObject,setScopeAlways,void,2,2,"() Use the setScopeAlways method to force an object to be SCOPE_ALWAYS for all clients.\n"
  160. "When an object is SCOPE_ALWAYS it is always ghosted. Therefore, if you have an object that should always be ghosted to all clients, use this method.\n"
  161. "@return No return value.\n"
  162. "@sa scopeToClient")
  163. {
  164. object->setScopeAlways();
  165. }
  166. void NetObject::setScopeAlways()
  167. {
  168. if(mNetFlags.test(Ghostable) && !mNetFlags.test(IsGhost))
  169. {
  170. mNetFlags.set(ScopeAlways);
  171. // if it's a ghost always object, add it to the ghost always set
  172. // for ClientReps created later.
  173. Sim::getGhostAlwaysSet()->addObject(this);
  174. // add it to all Connections that already exist.
  175. SimGroup *clientGroup = Sim::getClientGroup();
  176. SimGroup::iterator i;
  177. for(i = clientGroup->begin(); i != clientGroup->end(); i++)
  178. {
  179. NetConnection *con = (NetConnection *) (*i);
  180. if(con->isGhosting())
  181. con->objectInScope(this);
  182. }
  183. }
  184. }
  185. void NetObject::clearScopeAlways()
  186. {
  187. if(!mNetFlags.test(IsGhost))
  188. {
  189. mNetFlags.clear(ScopeAlways);
  190. Sim::getGhostAlwaysSet()->removeObject(this);
  191. // Un ghost this object from all the connections
  192. while(mFirstObjectRef)
  193. mFirstObjectRef->connection->detachObject(mFirstObjectRef);
  194. }
  195. }
  196. bool NetObject::onAdd()
  197. {
  198. if(mNetFlags.test(ScopeAlways))
  199. setScopeAlways();
  200. return Parent::onAdd();
  201. }
  202. void NetObject::onRemove()
  203. {
  204. while(mFirstObjectRef)
  205. mFirstObjectRef->connection->detachObject(mFirstObjectRef);
  206. Parent::onRemove();
  207. }
  208. //-----------------------------------------------------------------------------
  209. F32 NetObject::getUpdatePriority(CameraScopeQuery*, U32, S32 updateSkips)
  210. {
  211. return F32(updateSkips) * 0.1f;
  212. }
  213. U32 NetObject::packUpdate(NetConnection* conn, U32 mask, BitStream* stream)
  214. {
  215. return 0;
  216. }
  217. void NetObject::unpackUpdate(NetConnection*, BitStream*)
  218. {
  219. }
  220. void NetObject::onCameraScopeQuery(NetConnection *cr, CameraScopeQuery* /*camInfo*/)
  221. {
  222. // default behavior -
  223. // ghost everything that is ghostable
  224. for (SimSetIterator obj(Sim::getRootGroup()); *obj; ++obj)
  225. {
  226. NetObject* nobj = dynamic_cast<NetObject*>(*obj);
  227. if (nobj)
  228. {
  229. AssertFatal(!nobj->mNetFlags.test(NetObject::Ghostable) || !nobj->mNetFlags.test(NetObject::IsGhost),
  230. "NetObject::onCameraScopeQuery: object marked both ghostable and as ghost");
  231. // Some objects don't ever want to be ghosted
  232. if (!nobj->mNetFlags.test(NetObject::Ghostable))
  233. continue;
  234. if (!nobj->mNetFlags.test(NetObject::ScopeAlways))
  235. {
  236. // it's in scope...
  237. cr->objectInScope(nobj);
  238. }
  239. }
  240. }
  241. }
  242. //-----------------------------------------------------------------------------
  243. void NetObject::initPersistFields()
  244. {
  245. Parent::initPersistFields();
  246. }
  247. ConsoleMethod( NetObject, getGhostID, S32, 2, 2, "()\n @return Returns the ghost ID of the object")
  248. {
  249. return object->getNetIndex();
  250. }