Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

273 lines
6.3 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "entitylist_base.h"
  8. #include "ihandleentity.h"
  9. // memdbgon must be the last include file in a .cpp file!!!
  10. #include "tier0/memdbgon.h"
  11. enum
  12. {
  13. SERIAL_MASK = 0x7fff // the max value of a serial number, rolls back to 0 when it hits this limit
  14. };
  15. void CEntInfo::ClearLinks()
  16. {
  17. m_pPrev = m_pNext = this;
  18. }
  19. CBaseEntityList::CEntInfoList::CEntInfoList()
  20. {
  21. m_pHead = NULL;
  22. m_pTail = NULL;
  23. }
  24. // NOTE: Cut from UtlFixedLinkedList<>, UNDONE: Find a way to share this code
  25. void CBaseEntityList::CEntInfoList::LinkBefore( CEntInfo *pBefore, CEntInfo *pElement )
  26. {
  27. Assert( pElement );
  28. // Unlink it if it's in the list at the moment
  29. Unlink(pElement);
  30. // The element *after* our newly linked one is the one we linked before.
  31. pElement->m_pNext = pBefore;
  32. if (pBefore == NULL)
  33. {
  34. // In this case, we're linking to the end of the list, so reset the tail
  35. pElement->m_pPrev = m_pTail;
  36. m_pTail = pElement;
  37. }
  38. else
  39. {
  40. // Here, we're not linking to the end. Set the prev pointer to point to
  41. // the element we're linking.
  42. Assert( IsInList(pBefore) );
  43. pElement->m_pPrev = pBefore->m_pPrev;
  44. pBefore->m_pPrev = pElement;
  45. }
  46. // Reset the head if we linked to the head of the list
  47. if (pElement->m_pPrev == NULL)
  48. {
  49. m_pHead = pElement;
  50. }
  51. else
  52. {
  53. pElement->m_pPrev->m_pNext = pElement;
  54. }
  55. }
  56. void CBaseEntityList::CEntInfoList::LinkAfter( CEntInfo *pAfter, CEntInfo *pElement )
  57. {
  58. Assert( pElement );
  59. // Unlink it if it's in the list at the moment
  60. if ( IsInList(pElement) )
  61. Unlink(pElement);
  62. // The element *before* our newly linked one is the one we linked after
  63. pElement->m_pPrev = pAfter;
  64. if (pAfter == NULL)
  65. {
  66. // In this case, we're linking to the head of the list, reset the head
  67. pElement->m_pNext = m_pHead;
  68. m_pHead = pElement;
  69. }
  70. else
  71. {
  72. // Here, we're not linking to the end. Set the next pointer to point to
  73. // the element we're linking.
  74. Assert( IsInList(pAfter) );
  75. pElement->m_pNext = pAfter->m_pNext;
  76. pAfter->m_pNext = pElement;
  77. }
  78. // Reset the tail if we linked to the tail of the list
  79. if (pElement->m_pNext == NULL )
  80. {
  81. m_pTail = pElement;
  82. }
  83. else
  84. {
  85. pElement->m_pNext->m_pPrev = pElement;
  86. }
  87. }
  88. void CBaseEntityList::CEntInfoList::Unlink( CEntInfo *pElement )
  89. {
  90. if (IsInList(pElement))
  91. {
  92. // If we're the first guy, reset the head
  93. // otherwise, make our previous node's next pointer = our next
  94. if ( pElement->m_pPrev )
  95. {
  96. pElement->m_pPrev->m_pNext = pElement->m_pNext;
  97. }
  98. else
  99. {
  100. m_pHead = pElement->m_pNext;
  101. }
  102. // If we're the last guy, reset the tail
  103. // otherwise, make our next node's prev pointer = our prev
  104. if ( pElement->m_pNext )
  105. {
  106. pElement->m_pNext->m_pPrev = pElement->m_pPrev;
  107. }
  108. else
  109. {
  110. m_pTail = pElement->m_pPrev;
  111. }
  112. // This marks this node as not in the list,
  113. // but not in the free list either
  114. pElement->ClearLinks();
  115. }
  116. }
  117. bool CBaseEntityList::CEntInfoList::IsInList( CEntInfo *pElement )
  118. {
  119. return pElement->m_pPrev != pElement;
  120. }
  121. CBaseEntityList::CBaseEntityList()
  122. {
  123. // These are not in any list (yet)
  124. int i;
  125. for ( i = 0; i < NUM_ENT_ENTRIES; i++ )
  126. {
  127. m_EntPtrArray[i].ClearLinks();
  128. m_EntPtrArray[i].m_SerialNumber = (rand()& SERIAL_MASK); // generate random starting serial number
  129. m_EntPtrArray[i].m_pEntity = NULL;
  130. }
  131. // make a free list of the non-networkable entities
  132. // Initially, all the slots are free.
  133. for ( i=MAX_EDICTS+1; i < NUM_ENT_ENTRIES; i++ )
  134. {
  135. CEntInfo *pList = &m_EntPtrArray[i];
  136. m_freeNonNetworkableList.AddToTail( pList );
  137. }
  138. }
  139. CBaseEntityList::~CBaseEntityList()
  140. {
  141. CEntInfo *pList = m_activeList.Head();
  142. while ( pList )
  143. {
  144. CEntInfo *pNext = pList->m_pNext;
  145. RemoveEntityAtSlot( GetEntInfoIndex( pList ) );
  146. pList = pNext;
  147. }
  148. }
  149. CBaseHandle CBaseEntityList::AddNetworkableEntity( IHandleEntity *pEnt, int index, int iForcedSerialNum )
  150. {
  151. Assert( index >= 0 && index < MAX_EDICTS );
  152. return AddEntityAtSlot( pEnt, index, iForcedSerialNum );
  153. }
  154. CBaseHandle CBaseEntityList::AddNonNetworkableEntity( IHandleEntity *pEnt )
  155. {
  156. // Find a slot for it.
  157. CEntInfo *pSlot = m_freeNonNetworkableList.Head();
  158. if ( !pSlot )
  159. {
  160. Warning( "CBaseEntityList::AddNonNetworkableEntity: no free slots!\n" );
  161. AssertMsg( 0, ( "CBaseEntityList::AddNonNetworkableEntity: no free slots!\n" ) );
  162. return CBaseHandle();
  163. }
  164. // Move from the free list into the allocated list.
  165. m_freeNonNetworkableList.Unlink( pSlot );
  166. int iSlot = GetEntInfoIndex( pSlot );
  167. return AddEntityAtSlot( pEnt, iSlot, -1 );
  168. }
  169. void CBaseEntityList::RemoveEntity( CBaseHandle handle )
  170. {
  171. RemoveEntityAtSlot( handle.GetEntryIndex() );
  172. }
  173. CBaseHandle CBaseEntityList::AddEntityAtSlot( IHandleEntity *pEnt, int iSlot, int iForcedSerialNum )
  174. {
  175. // Init the CSerialEntity.
  176. CEntInfo *pSlot = &m_EntPtrArray[iSlot];
  177. Assert( pSlot->m_pEntity == NULL );
  178. pSlot->m_pEntity = pEnt;
  179. // Force the serial number (client-only)?
  180. if ( iForcedSerialNum != -1 )
  181. {
  182. pSlot->m_SerialNumber = iForcedSerialNum;
  183. #if !defined( CLIENT_DLL )
  184. // Only the client should force the serial numbers.
  185. Assert( false );
  186. #endif
  187. }
  188. // Update our list of active entities.
  189. m_activeList.AddToTail( pSlot );
  190. CBaseHandle retVal( iSlot, pSlot->m_SerialNumber );
  191. // Tell the entity to store its handle.
  192. pEnt->SetRefEHandle( retVal );
  193. // Notify any derived class.
  194. OnAddEntity( pEnt, retVal );
  195. return retVal;
  196. }
  197. void CBaseEntityList::RemoveEntityAtSlot( int iSlot )
  198. {
  199. Assert( iSlot >= 0 && iSlot < NUM_ENT_ENTRIES );
  200. CEntInfo *pInfo = &m_EntPtrArray[iSlot];
  201. if ( pInfo->m_pEntity )
  202. {
  203. pInfo->m_pEntity->SetRefEHandle( INVALID_EHANDLE );
  204. // Notify the derived class that we're about to remove this entity.
  205. OnRemoveEntity( pInfo->m_pEntity, CBaseHandle( iSlot, pInfo->m_SerialNumber ) );
  206. // Increment the serial # so ehandles go invalid.
  207. pInfo->m_pEntity = NULL;
  208. pInfo->m_SerialNumber = ( pInfo->m_SerialNumber+1)& SERIAL_MASK;
  209. m_activeList.Unlink( pInfo );
  210. // Add the slot back to the free list if it's a non-networkable entity.
  211. if ( iSlot >= MAX_EDICTS )
  212. {
  213. m_freeNonNetworkableList.AddToTail( pInfo );
  214. }
  215. }
  216. }
  217. void CBaseEntityList::OnAddEntity( IHandleEntity *pEnt, CBaseHandle handle )
  218. {
  219. }
  220. void CBaseEntityList::OnRemoveEntity( IHandleEntity *pEnt, CBaseHandle handle )
  221. {
  222. }