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.

465 lines
14 KiB

  1. //====== Copyright � 1996-2005, Valve Corporation, All rights reserved. =======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "commeditdoc.h"
  9. #include "tier1/keyvalues.h"
  10. #include "tier1/utlbuffer.h"
  11. #include "toolutils/enginetools_int.h"
  12. #include "filesystem.h"
  13. #include "commedittool.h"
  14. #include "toolframework/ienginetool.h"
  15. #include "dmecommentarynodeentity.h"
  16. #include "datamodel/idatamodel.h"
  17. #include "toolutils/attributeelementchoicelist.h"
  18. #include "commentarynodebrowserpanel.h"
  19. #include "vgui_controls/messagebox.h"
  20. //-----------------------------------------------------------------------------
  21. // Constructor
  22. //-----------------------------------------------------------------------------
  23. CCommEditDoc::CCommEditDoc( ICommEditDocCallback *pCallback ) : m_pCallback( pCallback )
  24. {
  25. m_hRoot = NULL;
  26. m_pTXTFileName[0] = 0;
  27. m_bDirty = false;
  28. g_pDataModel->InstallNotificationCallback( this );
  29. }
  30. CCommEditDoc::~CCommEditDoc()
  31. {
  32. g_pDataModel->RemoveNotificationCallback( this );
  33. }
  34. //-----------------------------------------------------------------------------
  35. // Inherited from INotifyUI
  36. //-----------------------------------------------------------------------------
  37. void CCommEditDoc::NotifyDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags )
  38. {
  39. OnDataChanged( pReason, nNotifySource, nNotifyFlags );
  40. }
  41. //-----------------------------------------------------------------------------
  42. // Gets the file name
  43. //-----------------------------------------------------------------------------
  44. const char *CCommEditDoc::GetTXTFileName()
  45. {
  46. return m_pTXTFileName;
  47. }
  48. void CCommEditDoc::SetTXTFileName( const char *pFileName )
  49. {
  50. Q_strncpy( m_pTXTFileName, pFileName, sizeof( m_pTXTFileName ) );
  51. Q_FixSlashes( m_pTXTFileName );
  52. SetDirty( true );
  53. }
  54. //-----------------------------------------------------------------------------
  55. // Dirty bits
  56. //-----------------------------------------------------------------------------
  57. void CCommEditDoc::SetDirty( bool bDirty )
  58. {
  59. m_bDirty = bDirty;
  60. }
  61. bool CCommEditDoc::IsDirty() const
  62. {
  63. return m_bDirty;
  64. }
  65. //-----------------------------------------------------------------------------
  66. // Saves/loads from file
  67. //-----------------------------------------------------------------------------
  68. bool CCommEditDoc::LoadFromFile( const char *pFileName )
  69. {
  70. Assert( !m_hRoot.Get() );
  71. CAppDisableUndoScopeGuard guard( "CCommEditDoc::LoadFromFile", 0 );
  72. SetDirty( false );
  73. if ( !pFileName[0] )
  74. return false;
  75. char mapname[ 256 ];
  76. // Compute the map name
  77. const char *pMaps = Q_stristr( pFileName, "\\maps\\" );
  78. if ( !pMaps )
  79. return false;
  80. // Build map name
  81. //int nNameLen = (int)( (size_t)pComm - (size_t)pMaps ) - 5;
  82. Q_StripExtension( pFileName, mapname, sizeof(mapname) );
  83. char *pszFileName = (char*)Q_UnqualifiedFileName(mapname);
  84. // Set the txt file name.
  85. // If we loaded an existing commentary file, keep the same filename.
  86. // If we loaded a .bsp, change the name & the extension.
  87. if ( !V_stricmp( Q_GetFileExtension( pFileName ), "bsp" ) )
  88. {
  89. const char *pCommentaryAppend = "_commentary.txt";
  90. Q_StripExtension( pFileName, m_pTXTFileName, sizeof(m_pTXTFileName)- strlen(pCommentaryAppend) - 1 );
  91. Q_strcat( m_pTXTFileName, pCommentaryAppend, sizeof( m_pTXTFileName ) );
  92. if ( g_pFileSystem->FileExists( m_pTXTFileName ) )
  93. {
  94. char pBuf[1024];
  95. Q_snprintf( pBuf, sizeof(pBuf), "File %s already exists!\n", m_pTXTFileName );
  96. m_pTXTFileName[0] = 0;
  97. vgui::MessageBox *pMessageBox = new vgui::MessageBox( "Unable to overwrite file!\n", pBuf, g_pCommEditTool );
  98. pMessageBox->DoModal( );
  99. return false;
  100. }
  101. DmFileId_t fileid = g_pDataModel->FindOrCreateFileId( m_pTXTFileName );
  102. m_hRoot = CreateElement<CDmElement>( "root", fileid );
  103. CDmrElementArray<> subkeys( m_hRoot->AddAttribute( "subkeys", AT_ELEMENT_ARRAY ) );
  104. CDmElement *pRoot2 = CreateElement<CDmElement>( "Entities", fileid );
  105. pRoot2->AddAttribute( "subkeys", AT_ELEMENT_ARRAY );
  106. subkeys.AddToTail( pRoot2 );
  107. g_pDataModel->SetFileRoot( fileid, m_hRoot );
  108. }
  109. else
  110. {
  111. char *pComm = Q_stristr( pszFileName, "_commentary" );
  112. if ( !pComm )
  113. {
  114. char pBuf[1024];
  115. Q_snprintf( pBuf, sizeof(pBuf), "File %s is not a commentary file!\nThe file name must end in _commentary.txt.\n", m_pTXTFileName );
  116. m_pTXTFileName[0] = 0;
  117. vgui::MessageBox *pMessageBox = new vgui::MessageBox( "Bad file name!\n", pBuf, g_pCommEditTool );
  118. pMessageBox->DoModal( );
  119. return false;
  120. }
  121. // Clip off the "_commentary" at the end of the filename
  122. *pComm = '\0';
  123. // This is not undoable
  124. CDisableUndoScopeGuard guard;
  125. CDmElement *pTXT = NULL;
  126. DmFileId_t fileid = g_pDataModel->RestoreFromFile( pFileName, NULL, "commentary", &pTXT );
  127. if ( fileid == DMFILEID_INVALID )
  128. {
  129. m_pTXTFileName[0] = 0;
  130. return false;
  131. }
  132. SetTXTFileName( pFileName );
  133. m_hRoot = pTXT;
  134. }
  135. guard.Release();
  136. SetDirty( false );
  137. char cmd[ 256 ];
  138. Q_snprintf( cmd, sizeof( cmd ), "disconnect; map %s\n", pszFileName );
  139. enginetools->Command( cmd );
  140. enginetools->Execute( );
  141. return true;
  142. }
  143. void CCommEditDoc::SaveToFile( )
  144. {
  145. if ( m_hRoot.Get() && m_pTXTFileName && m_pTXTFileName[0] )
  146. {
  147. g_pDataModel->SaveToFile( m_pTXTFileName, NULL, "keyvalues", "keyvalues", m_hRoot );
  148. }
  149. SetDirty( false );
  150. }
  151. //-----------------------------------------------------------------------------
  152. // Returns the root object
  153. //-----------------------------------------------------------------------------
  154. CDmElement *CCommEditDoc::GetRootObject()
  155. {
  156. return m_hRoot;
  157. }
  158. //-----------------------------------------------------------------------------
  159. // Returns the entity list
  160. //-----------------------------------------------------------------------------
  161. CDmAttribute *CCommEditDoc::GetEntityList()
  162. {
  163. CDmrElementArray<> mainKeys( m_hRoot, "subkeys" );
  164. if ( !mainKeys.IsValid() || mainKeys.Count() == 0 )
  165. return NULL;
  166. CDmeHandle<CDmElement> hEntityList;
  167. hEntityList = mainKeys[ 0 ];
  168. return hEntityList ? hEntityList->GetAttribute( "subkeys", AT_ELEMENT_ARRAY ) : NULL;
  169. }
  170. //-----------------------------------------------------------------------------
  171. // Purpose:
  172. //-----------------------------------------------------------------------------
  173. void CCommEditDoc::AddNewInfoRemarkable( const Vector &vecOrigin, const QAngle &angAngles )
  174. {
  175. CDmrCommentaryNodeEntityList entities( GetEntityList() );
  176. if ( !entities.IsValid() )
  177. return;
  178. CDmeCommentaryNodeEntity *pTarget;
  179. {
  180. CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Add Info Remarkable", "Add Info Remarkable" );
  181. pTarget = CreateElement<CDmeCommentaryNodeEntity>( "remarkable", entities.GetOwner()->GetFileId() );
  182. pTarget->SetName( "entity" );
  183. pTarget->SetValue( "classname", "info_remarkable" );
  184. pTarget->SetRenderOrigin( vecOrigin );
  185. pTarget->SetRenderAngles( angAngles );
  186. entities.AddToTail( pTarget );
  187. pTarget->MarkDirty();
  188. pTarget->DrawInEngine( true );
  189. }
  190. g_pCommEditTool->GetCommentaryNodeBrowser()->SelectNode( pTarget );
  191. }
  192. //-----------------------------------------------------------------------------
  193. // Purpose:
  194. //-----------------------------------------------------------------------------
  195. void CCommEditDoc::AddNewInfoRemarkable( void )
  196. {
  197. Vector vecOrigin;
  198. QAngle angAngles;
  199. float flFov;
  200. clienttools->GetLocalPlayerEyePosition( vecOrigin, angAngles, flFov );
  201. AddNewInfoRemarkable( vecOrigin, vec3_angle );
  202. }
  203. //-----------------------------------------------------------------------------
  204. // Purpose:
  205. //-----------------------------------------------------------------------------
  206. void CCommEditDoc::AddNewInfoTarget( const Vector &vecOrigin, const QAngle &angAngles )
  207. {
  208. CDmrCommentaryNodeEntityList entities( GetEntityList() );
  209. if ( !entities.IsValid() )
  210. return;
  211. CDmeCommentaryNodeEntity *pTarget;
  212. {
  213. CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Add Info Target", "Add Info Target" );
  214. pTarget = CreateElement<CDmeCommentaryNodeEntity>( "target", entities.GetOwner()->GetFileId() );
  215. pTarget->SetName( "entity" );
  216. pTarget->SetValue( "classname", "info_target" );
  217. pTarget->SetRenderOrigin( vecOrigin );
  218. pTarget->SetRenderAngles( angAngles );
  219. entities.AddToTail( pTarget );
  220. pTarget->MarkDirty();
  221. pTarget->DrawInEngine( true );
  222. }
  223. g_pCommEditTool->GetCommentaryNodeBrowser()->SelectNode( pTarget );
  224. }
  225. //-----------------------------------------------------------------------------
  226. // Purpose:
  227. //-----------------------------------------------------------------------------
  228. void CCommEditDoc::AddNewInfoTarget( void )
  229. {
  230. Vector vecOrigin;
  231. QAngle angAngles;
  232. float flFov;
  233. clienttools->GetLocalPlayerEyePosition( vecOrigin, angAngles, flFov );
  234. AddNewInfoTarget( vecOrigin, vec3_angle );
  235. }
  236. //-----------------------------------------------------------------------------
  237. // Purpose:
  238. //-----------------------------------------------------------------------------
  239. void CCommEditDoc::AddNewCommentaryNode( const Vector &vecOrigin, const QAngle &angAngles )
  240. {
  241. CDmrCommentaryNodeEntityList entities = GetEntityList();
  242. CDmeCommentaryNodeEntity *pNode;
  243. {
  244. CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Add Commentary Node", "Add Commentary Node" );
  245. pNode = CreateElement<CDmeCommentaryNodeEntity>( "node", entities.GetOwner()->GetFileId() );
  246. pNode->SetName( "entity" );
  247. pNode->SetValue( "classname", "point_commentary_node" );
  248. pNode->SetRenderOrigin( vecOrigin );
  249. pNode->SetRenderAngles( angAngles );
  250. pNode->SetValue( "precommands", "" );
  251. pNode->SetValue( "postcommands", "" );
  252. pNode->SetValue( "commentaryfile", "" );
  253. pNode->SetValue( "viewtarget", "" );
  254. pNode->SetValue( "viewposition", "" );
  255. pNode->SetValue<int>( "prevent_movement", 0 );
  256. pNode->SetValue( "speakers", "" );
  257. pNode->SetValue( "synopsis", "" );
  258. entities.AddToTail( pNode );
  259. pNode->MarkDirty();
  260. pNode->DrawInEngine( true );
  261. }
  262. g_pCommEditTool->GetCommentaryNodeBrowser()->SelectNode( pNode );
  263. }
  264. //-----------------------------------------------------------------------------
  265. // Purpose:
  266. //-----------------------------------------------------------------------------
  267. void CCommEditDoc::AddNewCommentaryNode( void )
  268. {
  269. Vector vecOrigin;
  270. QAngle angAngles;
  271. float flFov;
  272. clienttools->GetLocalPlayerEyePosition( vecOrigin, angAngles, flFov );
  273. AddNewCommentaryNode( vecOrigin, vec3_angle );
  274. }
  275. //-----------------------------------------------------------------------------
  276. // Deletes a commentary node
  277. //-----------------------------------------------------------------------------
  278. void CCommEditDoc::DeleteCommentaryNode( CDmElement *pRemoveNode )
  279. {
  280. CDmrCommentaryNodeEntityList entities = GetEntityList();
  281. int nCount = entities.Count();
  282. for ( int i = 0; i < nCount; ++i )
  283. {
  284. if ( pRemoveNode == entities[i] )
  285. {
  286. CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Delete Commentary Node", "Delete Commentary Node" );
  287. CDmeCommentaryNodeEntity *pNode = entities[ i ];
  288. pNode->DrawInEngine( false );
  289. entities.FastRemove( i );
  290. return;
  291. }
  292. }
  293. }
  294. //-----------------------------------------------------------------------------
  295. // Purpose:
  296. // Input : &vecOrigin -
  297. // &angAbsAngles -
  298. // Output : CDmeCommentaryNodeEntity
  299. //-----------------------------------------------------------------------------
  300. CDmeCommentaryNodeEntity *CCommEditDoc::GetCommentaryNodeForLocation( Vector &vecOrigin, QAngle &angAbsAngles )
  301. {
  302. CDmrCommentaryNodeEntityList entities = GetEntityList();
  303. int nCount = entities.Count();
  304. for ( int i = 0; i < nCount; ++i )
  305. {
  306. CDmeCommentaryNodeEntity *pNode = entities[ i ];
  307. if ( !pNode )
  308. continue;
  309. Vector &vecAngles = *(Vector*)(&pNode->GetRenderAngles());
  310. if ( pNode->GetRenderOrigin().DistTo( vecOrigin ) < 1e-3 && vecAngles.DistTo( *(Vector*)&angAbsAngles ) < 1e-1 )
  311. return pNode;
  312. }
  313. return NULL;
  314. }
  315. //-----------------------------------------------------------------------------
  316. // Populate string choice lists
  317. //-----------------------------------------------------------------------------
  318. bool CCommEditDoc::GetStringChoiceList( const char *pChoiceListType, CDmElement *pElement,
  319. const char *pAttributeName, bool bArrayElement, StringChoiceList_t &list )
  320. {
  321. if ( !Q_stricmp( pChoiceListType, "info_targets" ) )
  322. {
  323. CDmrCommentaryNodeEntityList entities = GetEntityList();
  324. StringChoice_t sChoice;
  325. sChoice.m_pValue = "";
  326. sChoice.m_pChoiceString = "";
  327. list.AddToTail( sChoice );
  328. int nCount = entities.Count();
  329. for ( int i = 0; i < nCount; ++i )
  330. {
  331. CDmeCommentaryNodeEntity *pNode = entities[ i ];
  332. if ( !pNode )
  333. continue;
  334. if ( !V_stricmp( pNode->GetClassName(), "info_target" ) )
  335. {
  336. StringChoice_t sChoice;
  337. sChoice.m_pValue = pNode->GetTargetName();
  338. sChoice.m_pChoiceString = pNode->GetTargetName();
  339. list.AddToTail( sChoice );
  340. }
  341. }
  342. return true;
  343. }
  344. return false;
  345. }
  346. //-----------------------------------------------------------------------------
  347. // Populate element choice lists
  348. //-----------------------------------------------------------------------------
  349. bool CCommEditDoc::GetElementChoiceList( const char *pChoiceListType, CDmElement *pElement,
  350. const char *pAttributeName, bool bArrayElement, ElementChoiceList_t &list )
  351. {
  352. if ( !Q_stricmp( pChoiceListType, "allelements" ) )
  353. {
  354. AddElementsRecursively( m_hRoot, list );
  355. return true;
  356. }
  357. if ( !Q_stricmp( pChoiceListType, "info_targets" ) )
  358. {
  359. CDmrCommentaryNodeEntityList entities = GetEntityList();
  360. bool bFound = false;
  361. int nCount = entities.Count();
  362. for ( int i = 0; i < nCount; ++i )
  363. {
  364. CDmeCommentaryNodeEntity *pNode = entities[ i ];
  365. if ( pNode && !V_stricmp( pNode->GetClassName(), "info_target" ) )
  366. {
  367. bFound = true;
  368. ElementChoice_t sChoice;
  369. sChoice.m_pValue = pNode;
  370. sChoice.m_pChoiceString = pNode->GetTargetName();
  371. list.AddToTail( sChoice );
  372. }
  373. }
  374. return bFound;
  375. }
  376. // by default, try to treat the choice list type as a Dme element type
  377. AddElementsRecursively( m_hRoot, list, pChoiceListType );
  378. return list.Count() > 0;
  379. }
  380. //-----------------------------------------------------------------------------
  381. // Called when data changes
  382. //-----------------------------------------------------------------------------
  383. void CCommEditDoc::OnDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags )
  384. {
  385. SetDirty( nNotifyFlags & NOTIFY_SETDIRTYFLAG ? true : false );
  386. m_pCallback->OnDocChanged( pReason, nNotifySource, nNotifyFlags );
  387. }