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.

1995 lines
53 KiB

  1. //====== Copyright � 1996-2005, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose: Core Movie Maker UI API
  4. //
  5. //=============================================================================
  6. #include "stdafx.h"
  7. #include "hammer.h"
  8. #include "mapview3d.h"
  9. #include <direct.h>
  10. #include "mapdoc.h"
  11. #include "foundrytool.h"
  12. #include "appframework/AppFramework.h"
  13. #include "vphysics_interface.h"
  14. #include "datacache/idatacache.h"
  15. #include "toolutils/basetoolsystem.h"
  16. #include "toolutils/recentfilelist.h"
  17. #include "toolutils/toolmenubar.h"
  18. #include "toolutils/toolswitchmenubutton.h"
  19. #include "toolutils/tooleditmenubutton.h"
  20. #include "toolutils/miniviewport.h"
  21. #include "toolutils/toolfilemenubutton.h"
  22. #include "toolutils/toolmenubutton.h"
  23. #include "vgui_controls/Menu.h"
  24. #include "tier1/KeyValues.h"
  25. #include "toolutils/enginetools_int.h"
  26. #include "toolframework/ienginetool.h"
  27. #include "vgui/IInput.h"
  28. #include "vgui/KeyCode.h"
  29. #include "vgui_controls/FileOpenDialog.h"
  30. #include "filesystem.h"
  31. #include "vgui/ilocalize.h"
  32. #include "dme_controls/elementpropertiestree.h"
  33. #include "tier0/icommandline.h"
  34. #include "materialsystem/imaterialsystem.h"
  35. #include "vguimatsurface/imatsystemsurface.h"
  36. #include "toolutils/savewindowpositions.h"
  37. #include "toolutils/toolwindowfactory.h"
  38. #include "tier3/tier3.h"
  39. #include "tier2/fileutils.h"
  40. #include "vgui/ivgui.h"
  41. #include "ihammer.h"
  42. #include "mainfrm.h"
  43. #include "vgui/keycode.h"
  44. #include "saveinfo.h"
  45. #include "foundry/iserverfoundry.h"
  46. #include "mapworld.h"
  47. #include "ToolManager.h"
  48. #include "map_shared.h"
  49. #include "scriplib.h"
  50. using namespace vgui;
  51. class CFoundryViewMenuButton;
  52. //-----------------------------------------------------------------------------
  53. // Singleton interfaces
  54. //-----------------------------------------------------------------------------
  55. const char *GetVGuiControlsModuleName()
  56. {
  57. return "FoundryTool";
  58. }
  59. //-----------------------------------------------------------------------------
  60. // Connect, disconnect
  61. //-----------------------------------------------------------------------------
  62. CreateInterfaceFn g_MainFactory = NULL;
  63. bool ConnectTools( CreateInterfaceFn factory )
  64. {
  65. g_MainFactory = factory;
  66. return (materials != NULL) && (g_pMatSystemSurface != NULL);
  67. }
  68. void DisconnectTools( )
  69. {
  70. }
  71. //-----------------------------------------------------------------------------
  72. // Implementation of the Foundry tool
  73. //-----------------------------------------------------------------------------
  74. class CFoundryTool : public CBaseToolSystem, public IServerFoundry, public IFileMenuCallbacks, public IFoundryTool
  75. {
  76. DECLARE_CLASS_SIMPLE( CFoundryTool, CBaseToolSystem );
  77. public:
  78. friend class CFoundryViewport;
  79. CFoundryTool();
  80. // Inherited from IToolSystem
  81. virtual const char *GetToolName() { return "Foundry"; }
  82. virtual const char *GetBindingsContextFile() { return "cfg/Foundry.kb"; }
  83. virtual bool Init( );
  84. virtual void Shutdown();
  85. virtual bool CanQuit( const char *pExitMsg );
  86. virtual void OnToolActivate();
  87. virtual void OnToolDeactivate();
  88. virtual void* QueryInterface( const char *pInterfaceName );
  89. virtual void ClientLevelInitPostEntity();
  90. virtual void ClientLevelShutdownPreEntity();
  91. virtual void ClientPostRender();
  92. virtual bool SetupEngineView( Vector &origin, QAngle &angles, float &fov );
  93. virtual bool TrapKey( ButtonCode_t key, bool down );
  94. // Inherited from IServerFoundry.
  95. virtual bool GetRestoredEntityReplacementData( int iHammerID, CUtlVector<char> &data );
  96. virtual void OnFinishedRestoreSavegame();
  97. virtual void MoveEntityTo( int nHammerID, const Vector &vPos, const QAngle &vAngles );
  98. virtual void MoveHammerViewTo( const Vector &vPos, const QAngle &vAngles );
  99. virtual void EngineGetMouseControl();
  100. virtual void EngineReleaseMouseControl();
  101. virtual void SelectEntities( int *pHammerIDs, int nIDs );
  102. virtual void SelectionClickInCenterOfView( const Vector &vPos, const QAngle &vAngles );
  103. // Inherited from IFileMenuCallbacks
  104. virtual int GetFileMenuItemsEnabled( );
  105. virtual void AddRecentFilesToMenu( vgui::Menu *menu );
  106. virtual bool GetPerforceFileName( char *pFileName, int nMaxLen );
  107. // Inherited from IFoundryDocCallback
  108. virtual void OnDocChanged( const char *pReason, int nNotifySource, int nNotifyFlags );
  109. virtual vgui::Panel *GetRootPanel() { return this; }
  110. // Inherited from CBaseToolSystem
  111. virtual vgui::HScheme GetToolScheme();
  112. virtual vgui::Menu *CreateActionMenu( vgui::Panel *pParent );
  113. virtual void OnCommand( const char *cmd );
  114. virtual const char *GetRegistryName() { return "FoundryTool"; }
  115. virtual vgui::MenuBar *CreateMenuBar( CBaseToolSystem *pParent );
  116. virtual void OnModeChanged();
  117. virtual CMiniViewport *CreateMiniViewport( vgui::Panel *parent );
  118. // Inherited from IFoundryTool
  119. virtual void DestroyEntity( int iHammerID );
  120. virtual bool UpdateEntity( int iHammerID, CUtlVector<char*> &keys, CUtlVector<char*> &values );
  121. virtual void RespawnEntitiesWithEdits( CMapClass **ppEntities, int nEntities );
  122. virtual void MoveEngineViewTo( const Vector &vPos, const QAngle &vAngles );
  123. virtual void SwitchToEngine();
  124. virtual void ConsoleCommand( const char *pConCommand );
  125. virtual bool ShouldRender3DModels();
  126. virtual void OnMapDocDestroy( CMapDoc *pDoc );
  127. public:
  128. MESSAGE_FUNC( OnNew, "OnNew" );
  129. MESSAGE_FUNC( OnOpen, "OnOpen" );
  130. MESSAGE_FUNC( OnSave, "OnSave" );
  131. MESSAGE_FUNC( OnSaveAs, "OnSaveAs" );
  132. MESSAGE_FUNC( OnClose, "OnClose" );
  133. MESSAGE_FUNC( OnCloseNoSave, "OnCloseNoSave" );
  134. MESSAGE_FUNC( OnMarkNotDirty, "OnMarkNotDirty" );
  135. MESSAGE_FUNC( OnExit, "OnExit" );
  136. // Commands related to the edit menu
  137. KEYBINDING_FUNC( undo, KEY_Z, vgui::MODIFIER_CONTROL, OnUndo, "#undo_help", 0 );
  138. KEYBINDING_FUNC( redo, KEY_Z, vgui::MODIFIER_CONTROL | vgui::MODIFIER_SHIFT, OnRedo, "#redo_help", 0 );
  139. void OnDescribeUndo();
  140. // Methods related to the Foundry menu
  141. MESSAGE_FUNC( OnUpdateHammerEntity, "UpdateHammerEntity" );
  142. MESSAGE_FUNC( OnReload, "ReloadMap" );
  143. MESSAGE_FUNC( OnReloadFromSave, "ReloadFromSave" );
  144. MESSAGE_FUNC( OnReloadFromSaveSlamEnts, "ReloadFromSaveSlamEnts" );
  145. // Methods related to the view menu
  146. MESSAGE_FUNC( OnDefaultLayout, "OnDefaultLayout" );
  147. MESSAGE_FUNC( OnDrawHammerEntities, "OnDrawHammerEntities" );
  148. MESSAGE_FUNC( OnDrawHammerModels, "OnDrawHammerModels" );
  149. MESSAGE_FUNC( OnDrawEntityHighlights, "OnDrawEntityHighlights" );
  150. MESSAGE_FUNC( OnDrawGameEntities, "OnDrawGameEntities" );
  151. MESSAGE_FUNC( OnSyncHammerView, "OnSyncHammerView" );
  152. void SetDefaultMiniViewportBounds( vgui::Panel *pMiniViewport );
  153. void PerformNew();
  154. void OpenFileFromHistory( int slot );
  155. void OpenSpecificFile( const char *pFileName );
  156. virtual void SetupFileOpenDialog( vgui::FileOpenDialog *pDialog, bool bOpenFile, const char *pFileFormat, KeyValues *pContextKeyValues );
  157. virtual bool OnReadFileFromDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues );
  158. virtual bool OnWriteFileToDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues );
  159. virtual void OnFileOperationCompleted( const char *pFileType, bool bWroteFile, vgui::FileOpenStateMachine::CompletionState_t state, KeyValues *pContextKeyValues );
  160. // returns the document
  161. CMapDoc* GetDocument();
  162. private:
  163. // Called by the engine on exit.
  164. static bool StaticQuitHandler( void *pvUserData );
  165. bool GetEntityVMFText( CMapClass *pClass, CUtlVector<char> &data );
  166. // Loads up a new document
  167. bool LoadDocument( const char *pDocName );
  168. // Updates the menu bar based on the current file
  169. void UpdateMenuBar( );
  170. void MiniViewport_OnMousePressed( vgui::MouseCode code );
  171. virtual const char *GetLogoTextureName();
  172. // Creates, destroys tools
  173. void CreateTools();
  174. void DestroyTools();
  175. // Initializes the tools
  176. void InitTools();
  177. // Shows, toggles tool windows
  178. void ToggleToolWindow( Panel *tool, char const *toolName );
  179. void ShowToolWindow( Panel *tool, char const *toolName, bool visible );
  180. // Kills all tool windows
  181. void DestroyToolContainers();
  182. // Used to hook DME VMF entities into the render lists
  183. void DrawVMFEntitiesInEngine( bool bDrawInEngine );
  184. void AddOriginalEntities( CUtlBuffer &entityBuf, const char *pActualEntityData );
  185. void AddVMFEntities( CUtlBuffer &entityBuf, const char *pActualEntityData );
  186. const char* GenerateEntityData( const char *pActualEntityData );
  187. const char* GetVMFFileName();
  188. bool IsDocumentDirty();
  189. private:
  190. // Document
  191. CMapDoc *m_pMapDoc; // The REAL document from Hammer.
  192. char m_pBSPFileName[MAX_PATH];
  193. // Hammer
  194. IHammer *m_pHammer;
  195. Vector m_v3dViewOrigin;
  196. QAngle m_v3dViewAngles;
  197. float m_fl3dViewFOV;
  198. // The menu bar
  199. CToolFileMenuBar *m_pMenuBar;
  200. CFoundryViewMenuButton *m_pViewMenuButton;
  201. // Separate undo context for the act busy tool
  202. CToolWindowFactory< ToolWindow > m_ToolWindowFactory;
  203. CUtlVector< DmElementHandle_t > m_toolElements;
  204. CUtlVector<int> m_SavegameRestoredEnts;
  205. };
  206. //-----------------------------------------------------------------------------
  207. // Singleton
  208. //-----------------------------------------------------------------------------
  209. CFoundryTool *g_pFoundryToolImp = NULL;
  210. IFoundryTool *g_pFoundryTool = NULL;
  211. void CreateTools()
  212. {
  213. g_pFoundryTool = g_pFoundryToolImp = new CFoundryTool();
  214. }
  215. static ConVar foundry_draw_hammer_models( "foundry_draw_hammer_models", "0", 0 );
  216. static ConVar foundry_draw_hammer_entities( "foundry_draw_hammer_entities", "1", 0 );
  217. static ConVar foundry_auto_pause( "foundry_auto_pause", "2", 0, "If 1, Foundry pauses the game when the engine window loses focus. If 2, Foundry disables AI when the engine window loses focus." );
  218. static bool GetDrawEntitiesCvar()
  219. {
  220. static ConVarRef val( "r_drawentities" );
  221. return val.GetBool();
  222. }
  223. CON_COMMAND( foundry_sync_engine_view, "Move engine's 3D view to the same position as Hammer's 3D view." )
  224. {
  225. CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
  226. if ( !pDoc )
  227. return;
  228. POSITION p = pDoc->GetFirstViewPosition();
  229. while (p != NULL)
  230. {
  231. CMapView3D *pView = dynamic_cast< CMapView3D* >( pDoc->GetNextView(p) );
  232. if ( pView )
  233. {
  234. CCamera *pCamera = pView->GetCamera();
  235. Vector vPos;
  236. pCamera->GetViewPoint( vPos );
  237. QAngle vEngineAngles = pCamera->GetAngles();
  238. vEngineAngles[YAW] = -vEngineAngles[YAW] + 90.0f; // translate from Hammer's 3D renderer angles to engine angles
  239. g_pFoundryTool->MoveEngineViewTo( vPos, vEngineAngles );
  240. return;
  241. }
  242. }
  243. }
  244. CON_COMMAND( foundry_send_ents_to_engine, "Send selected entities in Hammer into the engine." )
  245. {
  246. CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
  247. if ( !g_pFoundryTool || !pDoc )
  248. return;
  249. CSelection *pSelection = pDoc->GetSelection();
  250. if ( !pSelection || pSelection->IsEmpty() )
  251. return;
  252. CUtlVector<CMapClass*> toRespawn;
  253. const CMapObjectList *pObjectList = pSelection->GetList();
  254. for ( int i=0; i < pObjectList->Count(); i++ )
  255. {
  256. CMapClass *pClass = (CUtlReference< CMapClass >)pObjectList->Element( i );
  257. toRespawn.AddToTail( pClass );
  258. }
  259. g_pFoundryTool->RespawnEntitiesWithEdits( toRespawn.Base(), toRespawn.Count() );
  260. }
  261. CON_COMMAND( foundry_move_focus_to_engine, "Send focus to the engine." )
  262. {
  263. HWND hWnd = (HWND)enginetools->GetEngineHwnd();
  264. RECT rcWindow;
  265. ::GetWindowRect( hWnd, &rcWindow );
  266. SetCursorPos( (rcWindow.left + rcWindow.right) / 2, (rcWindow.top + rcWindow.bottom) / 2 );
  267. ::SetFocus( hWnd );
  268. }
  269. class CVisGroupEntList
  270. {
  271. public:
  272. CUtlVector<CMapClass*> m_Entities;
  273. CVisGroup *m_pGroup;
  274. };
  275. BOOL FindEntitiesInVisGroupCallback( CMapEntity *pObject, CVisGroupEntList *pList )
  276. {
  277. CMapClass *pClass = dynamic_cast< CMapClass* >( pObject );
  278. if ( pClass && pClass->IsInVisGroup( pList->m_pGroup ) )
  279. pList->m_Entities.AddToTail( pClass );
  280. return TRUE;
  281. }
  282. CON_COMMAND( foundry_spawn_visgroup, "Spawn all the entities in the specified visgroup." )
  283. {
  284. CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
  285. if ( !g_pFoundryTool || !pDoc )
  286. return;
  287. if ( args.ArgC() < 2 )
  288. {
  289. Warning( "Visgroup name required.\n" );
  290. return;
  291. }
  292. const char *pVisGroupName = args.Arg( 1 );
  293. CVisGroup *pVisGroup = pDoc->VisGroups_GroupForName( pVisGroupName, false );
  294. if ( !pVisGroup )
  295. pVisGroup = pDoc->VisGroups_GroupForName( pVisGroupName, true );
  296. if ( !pVisGroup )
  297. {
  298. Warning( "Can't find visgroup '%s'\n", pVisGroupName );
  299. return;
  300. }
  301. // Now find all objects.
  302. CVisGroupEntList theList;
  303. theList.m_pGroup = pVisGroup;
  304. pDoc->GetMapWorld()->EnumChildren( (ENUMMAPCHILDRENPROC)FindEntitiesInVisGroupCallback, (DWORD)&theList, MAPCLASS_TYPE(CMapEntity) );
  305. // Recreate them all.
  306. g_pFoundryTool->RespawnEntitiesWithEdits( theList.m_Entities.Base(), theList.m_Entities.Count() );
  307. }
  308. CON_COMMAND( foundry_remove_selected, "Remove selected entities." )
  309. {
  310. CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
  311. if ( !g_pFoundryTool || !pDoc )
  312. return;
  313. CSelection *pSelection = pDoc->GetSelection();
  314. if ( !pSelection || pSelection->IsEmpty() )
  315. return;
  316. const CMapObjectList *pObjectList = pSelection->GetList();
  317. for ( int i=0; i < pObjectList->Count(); i++ )
  318. {
  319. CMapClass *pClass = (CUtlReference< CMapClass >)pObjectList->Element( i );
  320. // Update in Foundry if we are running in that mode
  321. if ( g_pFoundryTool && pClass )
  322. {
  323. servertools->RemoveEntity( pClass->GetHammerID() );
  324. }
  325. }
  326. }
  327. //-----------------------------------------------------------------------------
  328. // Constructor
  329. //-----------------------------------------------------------------------------
  330. CFoundryTool::CFoundryTool()
  331. {
  332. m_pBSPFileName[0] = 0;
  333. m_pMenuBar = NULL;
  334. m_pMapDoc = NULL;
  335. m_pHammer = NULL;
  336. m_v3dViewOrigin.Init();
  337. m_v3dViewAngles.Init();
  338. m_fl3dViewFOV = 90;
  339. m_pViewMenuButton = NULL;
  340. }
  341. //-----------------------------------------------------------------------------
  342. // Init, shutdown
  343. //-----------------------------------------------------------------------------
  344. bool CFoundryTool::Init( )
  345. {
  346. m_pMapDoc = NULL;
  347. m_RecentFiles.LoadFromRegistry( GetRegistryName() );
  348. // NOTE: This has to happen before BaseClass::Init
  349. g_pVGuiLocalize->AddFile( "resource/toolfoundry_%language%.txt" );
  350. if ( !BaseClass::Init( ) )
  351. return false;
  352. enginetools->InstallQuitHandler( this, &CFoundryTool::StaticQuitHandler );
  353. // Startup Hammer.
  354. m_pHammer = (IHammer*)Sys_GetFactoryThis()( INTERFACEVERSION_HAMMER, NULL );
  355. if ( !m_pHammer )
  356. Error( "Unable to load hammer_dll.dll" );
  357. char gamedir[MAX_PATH];
  358. enginetools->GetGameDir( gamedir, sizeof( gamedir ) );
  359. m_pHammer->InitFoundryMode( g_MainFactory, NULL, gamedir );
  360. return true;
  361. }
  362. void CFoundryTool::Shutdown()
  363. {
  364. m_RecentFiles.SaveToRegistry( GetRegistryName() );
  365. {
  366. CDisableUndoScopeGuard guard;
  367. int nElements = m_toolElements.Count();
  368. for ( int i = 0; i < nElements; ++i )
  369. {
  370. g_pDataModel->DestroyElement( m_toolElements[ i ] );
  371. }
  372. }
  373. m_pMapDoc = NULL;
  374. BaseClass::Shutdown();
  375. }
  376. //-----------------------------------------------------------------------------
  377. // returns the document
  378. //-----------------------------------------------------------------------------
  379. inline CMapDoc *CFoundryTool::GetDocument()
  380. {
  381. return m_pMapDoc;
  382. }
  383. //-----------------------------------------------------------------------------
  384. // Tool activation/deactivation
  385. //-----------------------------------------------------------------------------
  386. void CFoundryTool::OnToolActivate()
  387. {
  388. BaseClass::OnToolActivate();
  389. }
  390. void CFoundryTool::OnToolDeactivate()
  391. {
  392. BaseClass::OnToolDeactivate();
  393. }
  394. //-----------------------------------------------------------------------------
  395. // Used to hook DME VMF entities into the render lists
  396. //-----------------------------------------------------------------------------
  397. void CFoundryTool::DrawVMFEntitiesInEngine( bool bDrawInEngine )
  398. {
  399. }
  400. void CFoundryTool::ClientLevelInitPostEntity()
  401. {
  402. BaseClass::ClientLevelInitPostEntity();
  403. DrawVMFEntitiesInEngine( true );
  404. }
  405. void CFoundryTool::ClientLevelShutdownPreEntity()
  406. {
  407. DrawVMFEntitiesInEngine( false );
  408. BaseClass::ClientLevelShutdownPreEntity();
  409. }
  410. //-----------------------------------------------------------------------------
  411. // Derived classes can implement this to get a new scheme to be applied to this tool
  412. //-----------------------------------------------------------------------------
  413. vgui::HScheme CFoundryTool::GetToolScheme()
  414. {
  415. return vgui::scheme()->LoadSchemeFromFile( "Resource/BoxRocket.res", "BoxRocket" );
  416. }
  417. //-----------------------------------------------------------------------------
  418. //
  419. // The View menu
  420. //
  421. //-----------------------------------------------------------------------------
  422. class CFoundryViewMenuButton : public CToolMenuButton
  423. {
  424. DECLARE_CLASS_SIMPLE( CFoundryViewMenuButton, CToolMenuButton );
  425. public:
  426. CFoundryViewMenuButton( CFoundryTool *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget );
  427. virtual void OnShowMenu(vgui::Menu *menu);
  428. public:
  429. int m_menuitemidDrawHammerEntities;
  430. int m_menuitemidDrawHammerModels;
  431. int m_menuitemidDrawEntityHighlights;
  432. int m_menuitemidDrawGameEntities;
  433. private:
  434. CFoundryTool *m_pTool;
  435. };
  436. CFoundryViewMenuButton::CFoundryViewMenuButton( CFoundryTool *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget )
  437. : BaseClass( parent, panelName, text, pActionSignalTarget )
  438. {
  439. m_pTool = parent;
  440. AddMenuItem( "defaultlayout", "#FoundryViewDefault", new KeyValues( "OnDefaultLayout" ), pActionSignalTarget );
  441. m_menuitemidDrawHammerEntities = AddCheckableMenuItem( "drawhammerentities", "#FoundryViewDrawHammerEntities", new KeyValues( "OnDrawHammerEntities" ), pActionSignalTarget );
  442. m_pMenu->SetMenuItemChecked( m_menuitemidDrawHammerEntities, foundry_draw_hammer_entities.GetBool() );
  443. m_menuitemidDrawHammerModels = AddCheckableMenuItem( "drawhammermodels", "#FoundryViewDrawHammerModels", new KeyValues( "OnDrawHammerModels" ), pActionSignalTarget );
  444. m_pMenu->SetMenuItemChecked( m_menuitemidDrawHammerModels, foundry_draw_hammer_models.GetBool() );
  445. m_menuitemidDrawEntityHighlights = AddCheckableMenuItem( "DrawEntityHighlights", "#FoundryViewDrawEntityHighlights", new KeyValues( "OnDrawEntityHighlights" ), pActionSignalTarget );
  446. m_pMenu->SetMenuItemChecked( m_menuitemidDrawEntityHighlights, true );
  447. m_menuitemidDrawGameEntities = AddCheckableMenuItem( "drawgameentities", "#FoundryViewDrawGameEntities", new KeyValues( "OnDrawGameEntities" ), pActionSignalTarget );
  448. m_pMenu->SetMenuItemChecked( m_menuitemidDrawGameEntities, GetDrawEntitiesCvar() );
  449. AddMenuItem( "synchammerview", "#FoundrySyncHammerView", new KeyValues( "OnSyncHammerView" ), pActionSignalTarget );
  450. SetMenu(m_pMenu);
  451. }
  452. void CFoundryViewMenuButton::OnShowMenu(vgui::Menu *menu)
  453. {
  454. BaseClass::OnShowMenu( menu );
  455. /*
  456. // Update the menu
  457. int id;
  458. if ( m_pTool->GetDocument() )
  459. {
  460. id = m_Items.Find( "properties" );
  461. m_pMenu->SetItemEnabled( id, true );
  462. Panel *p;
  463. p = m_pTool->GetProperties();
  464. Assert( p );
  465. m_pMenu->SetMenuItemChecked( id, ( p && p->GetParent() ) ? true : false );
  466. id = m_Items.Find( "entityreport" );
  467. m_pMenu->SetItemEnabled( id, true );
  468. p = m_pTool->GetEntityReport();
  469. Assert( p );
  470. m_pMenu->SetMenuItemChecked( id, ( p && p->GetParent() ) ? true : false );
  471. }
  472. else
  473. {
  474. id = m_Items.Find( "properties" );
  475. m_pMenu->SetItemEnabled( id, false );
  476. id = m_Items.Find( "entityreport" );
  477. m_pMenu->SetItemEnabled( id, false );
  478. }
  479. */
  480. }
  481. //-----------------------------------------------------------------------------
  482. //
  483. // The Tool menu
  484. //
  485. //-----------------------------------------------------------------------------
  486. class CFoundryToolMenuButton : public CToolMenuButton
  487. {
  488. DECLARE_CLASS_SIMPLE( CFoundryToolMenuButton, CToolMenuButton );
  489. public:
  490. CFoundryToolMenuButton( CFoundryTool *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget );
  491. virtual void OnShowMenu(vgui::Menu *menu);
  492. private:
  493. CFoundryTool *m_pTool;
  494. };
  495. CFoundryToolMenuButton::CFoundryToolMenuButton( CFoundryTool *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget )
  496. : BaseClass( parent, panelName, text, pActionSignalTarget )
  497. {
  498. m_pTool = parent;
  499. AddMenuItem( "updateentity", "#FoundryUpdateHammerEntity", new KeyValues( "UpdateHammerEntity" ), pActionSignalTarget );
  500. AddMenuItem( "reload", "#FoundryReload", new KeyValues( "ReloadMap" ), pActionSignalTarget );
  501. AddMenuItem( "reloadsave", "#FoundryReloadFromSave", new KeyValues( "ReloadFromSave" ), pActionSignalTarget );
  502. AddMenuItem( "reloadsaveslaments", "#FoundryReloadReplaceEnts", new KeyValues( "ReloadFromSaveSlamEnts" ), pActionSignalTarget );
  503. SetMenu(m_pMenu);
  504. }
  505. void CFoundryToolMenuButton::OnShowMenu(vgui::Menu *menu)
  506. {
  507. BaseClass::OnShowMenu( menu );
  508. // Update the menu
  509. int id;
  510. CMapDoc *pDoc = m_pTool->GetDocument();
  511. id = m_Items.Find( "reload" );
  512. m_pMenu->SetItemEnabled( id, pDoc != NULL );
  513. id = m_Items.Find( "reloadsave" );
  514. m_pMenu->SetItemEnabled( id, pDoc != NULL );
  515. id = m_Items.Find( "reloadsaveslaments" );
  516. m_pMenu->SetItemEnabled( id, pDoc != NULL );
  517. }
  518. //-----------------------------------------------------------------------------
  519. // Initializes the menu bar
  520. //-----------------------------------------------------------------------------
  521. vgui::MenuBar *CFoundryTool::CreateMenuBar( CBaseToolSystem *pParent )
  522. {
  523. m_pMenuBar = new CToolFileMenuBar( pParent, "Main Menu Bar" );
  524. // Sets info in the menu bar
  525. char title[ 64 ];
  526. ComputeMenuBarTitle( title, sizeof( title ) );
  527. m_pMenuBar->SetInfo( title );
  528. m_pMenuBar->SetToolName( GetToolName() );
  529. // Add menu buttons
  530. CToolMenuButton *pFileButton = CreateToolFileMenuButton( m_pMenuBar, "File", "&File", GetActionTarget(), this );
  531. CToolMenuButton *pEditButton = CreateToolEditMenuButton( this, "Edit", "&Edit", GetActionTarget() );
  532. CFoundryToolMenuButton *pToolButton = new CFoundryToolMenuButton( this, "Foundry", "F&oundry", GetActionTarget() );
  533. m_pViewMenuButton = new CFoundryViewMenuButton( this, "View", "&View", GetActionTarget() );
  534. CToolMenuButton *pSwitchButton = CreateToolSwitchMenuButton( m_pMenuBar, "Switcher", "&Tools", GetActionTarget() );
  535. m_pMenuBar->AddButton( pFileButton );
  536. m_pMenuBar->AddButton( pEditButton );
  537. m_pMenuBar->AddButton( pToolButton );
  538. m_pMenuBar->AddButton( m_pViewMenuButton );
  539. m_pMenuBar->AddButton( pSwitchButton );
  540. return m_pMenuBar;
  541. }
  542. // Acts like a viewport but passes mouse input into Foundry.
  543. class CFoundryViewport : public CMiniViewport
  544. {
  545. public:
  546. DECLARE_CLASS_SIMPLE( CFoundryViewport, CMiniViewport );
  547. CFoundryViewport( CFoundryTool *pFoundryTool, vgui::Panel *pParent ) :
  548. CMiniViewport( pParent, "MiniViewport" )
  549. {
  550. m_pFoundryTool = pFoundryTool;
  551. }
  552. virtual void OnMousePressed( vgui::MouseCode code )
  553. {
  554. m_pFoundryTool->MiniViewport_OnMousePressed( code );
  555. }
  556. private:
  557. CFoundryTool *m_pFoundryTool;
  558. };
  559. CMiniViewport* CFoundryTool::CreateMiniViewport( vgui::Panel *parent )
  560. {
  561. int w, h;
  562. surface()->GetScreenSize( w, h );
  563. CMiniViewport *vp = new CFoundryViewport( this, parent );
  564. Assert( vp );
  565. vp->SetVisible( true );
  566. SetDefaultMiniViewportBounds( vp );
  567. return vp;
  568. }
  569. void CFoundryTool::MiniViewport_OnMousePressed( vgui::MouseCode code )
  570. {
  571. if ( !m_pMapDoc )
  572. return;
  573. CMapView3D *pView = m_pMapDoc->GetFirst3DView();
  574. if ( !pView )
  575. return;
  576. if ( code == MOUSE_LEFT )
  577. {
  578. int x, y;
  579. input()->GetCursorPos( x, y );
  580. ScreenToLocal( x, y );
  581. pView->Foundry_OnLButtonDown( x, y );
  582. }
  583. }
  584. //-----------------------------------------------------------------------------
  585. // Updates the menu bar based on the current file
  586. //-----------------------------------------------------------------------------
  587. void CFoundryTool::UpdateMenuBar( )
  588. {
  589. if ( !m_pMapDoc )
  590. {
  591. m_pMenuBar->SetFileName( "#FoundryNoFile" );
  592. return;
  593. }
  594. const char *pVMFFile = GetVMFFileName();
  595. if ( !pVMFFile[0] )
  596. {
  597. m_pMenuBar->SetFileName( "#FoundryNoFile" );
  598. return;
  599. }
  600. if ( IsDocumentDirty() )
  601. {
  602. char sz[ 512 ];
  603. Q_snprintf( sz, sizeof( sz ), "* %s", pVMFFile );
  604. m_pMenuBar->SetFileName( sz );
  605. }
  606. else
  607. {
  608. m_pMenuBar->SetFileName( pVMFFile );
  609. }
  610. }
  611. //-----------------------------------------------------------------------------
  612. // Destroys all tool windows
  613. //-----------------------------------------------------------------------------
  614. void CFoundryTool::DestroyToolContainers()
  615. {
  616. int c = ToolWindow::GetToolWindowCount();
  617. for ( int i = c - 1; i >= 0 ; --i )
  618. {
  619. ToolWindow *kill = ToolWindow::GetToolWindow( i );
  620. delete kill;
  621. }
  622. }
  623. //-----------------------------------------------------------------------------
  624. // Sets up the default layout
  625. //-----------------------------------------------------------------------------
  626. void CFoundryTool::OnDefaultLayout()
  627. {
  628. DestroyToolContainers();
  629. }
  630. void CFoundryTool::OnDrawHammerEntities()
  631. {
  632. foundry_draw_hammer_entities.SetValue( !foundry_draw_hammer_entities.GetInt() );
  633. if ( m_pViewMenuButton )
  634. {
  635. vgui::Menu *pMenu = m_pViewMenuButton->GetMenu();
  636. if ( pMenu )
  637. pMenu->SetMenuItemChecked( m_pViewMenuButton->m_menuitemidDrawHammerEntities, foundry_draw_hammer_entities.GetBool() );
  638. }
  639. }
  640. void CFoundryTool::OnDrawHammerModels()
  641. {
  642. foundry_draw_hammer_models.SetValue( !foundry_draw_hammer_models.GetInt() );
  643. if ( m_pViewMenuButton )
  644. {
  645. vgui::Menu *pMenu = m_pViewMenuButton->GetMenu();
  646. if ( pMenu )
  647. pMenu->SetMenuItemChecked( m_pViewMenuButton->m_menuitemidDrawHammerModels, foundry_draw_hammer_models.GetBool() );
  648. }
  649. }
  650. void CFoundryTool::OnDrawGameEntities()
  651. {
  652. bool bDrawGameEntities = !GetDrawEntitiesCvar();
  653. // Update convar
  654. char szConCommand[50];
  655. V_snprintf( szConCommand, 50, "r_drawentities %i\n", (int)bDrawGameEntities);
  656. enginetools->Command( szConCommand );
  657. // Update checkmark in menu
  658. if ( m_pViewMenuButton )
  659. {
  660. vgui::Menu *pMenu = m_pViewMenuButton->GetMenu();
  661. if ( pMenu )
  662. {
  663. pMenu->SetMenuItemChecked( m_pViewMenuButton->m_menuitemidDrawGameEntities, bDrawGameEntities );
  664. }
  665. }
  666. }
  667. void CFoundryTool::OnSyncHammerView()
  668. {
  669. enginetools->Command( "foundry_sync_hammer_view\n" );
  670. }
  671. void CFoundryTool::OnDrawEntityHighlights()
  672. {
  673. ConVar *pCv = ( ConVar * )cvar->FindVar( "cl_foundry_ShowEntityHighlights" );
  674. if ( pCv )
  675. {
  676. pCv->SetValue( !pCv->GetInt() );
  677. if ( m_pViewMenuButton )
  678. {
  679. vgui::Menu *pMenu = m_pViewMenuButton->GetMenu();
  680. if ( pMenu )
  681. pMenu->SetMenuItemChecked( m_pViewMenuButton->m_menuitemidDrawEntityHighlights, pCv->GetBool() );
  682. }
  683. }
  684. }
  685. void CFoundryTool::SetDefaultMiniViewportBounds( vgui::Panel *pMiniViewport )
  686. {
  687. int menuBarY = m_pMenuBar->GetTall();
  688. int mainPanelWidth, mainPanelHeight;
  689. GetSize( mainPanelWidth, mainPanelHeight );
  690. int padding = 3;
  691. int left = padding;
  692. int top = menuBarY + padding;
  693. int width = mainPanelWidth - padding*2;
  694. int height = (mainPanelHeight - menuBarY) - top;
  695. pMiniViewport->SetBounds( left, top, width, height );
  696. }
  697. //-----------------------------------------------------------------------------
  698. // Creates
  699. //-----------------------------------------------------------------------------
  700. void CFoundryTool::CreateTools()
  701. {
  702. /*
  703. if ( !m_hProperties.Get() )
  704. {
  705. m_hProperties = new CBasePropertiesContainer( NULL, NULL, NULL );
  706. }
  707. if ( !m_hEntityReport.Get() )
  708. {
  709. m_hEntityReport = new CEntityReportPanel( NULL, this, "EntityReportPanel" );
  710. }
  711. RegisterToolWindow( m_hProperties );
  712. RegisterToolWindow( m_hEntityReport );
  713. */
  714. }
  715. //-----------------------------------------------------------------------------
  716. // Initializes the tools
  717. //-----------------------------------------------------------------------------
  718. void CFoundryTool::InitTools()
  719. {
  720. // FIXME: There are no tool windows here; how should this work?
  721. // These panels are saved
  722. //windowposmgr->RegisterPanel( "properties", m_hProperties, false );
  723. //windowposmgr->RegisterPanel( "entityreport", m_hEntityReport, false );
  724. OnDefaultLayout();
  725. windowposmgr->LoadPositions( "cfg/foundry.txt", this, &m_ToolWindowFactory, "Foundry" );
  726. }
  727. void CFoundryTool::DestroyTools()
  728. {
  729. int c = ToolWindow::GetToolWindowCount();
  730. for ( int i = c - 1; i >= 0 ; --i )
  731. {
  732. ToolWindow *kill = ToolWindow::GetToolWindow( i );
  733. delete kill;
  734. }
  735. UnregisterAllToolWindows();
  736. }
  737. void CFoundryTool::ShowToolWindow( Panel *tool, char const *toolName, bool visible )
  738. {
  739. Assert( tool );
  740. if ( tool->GetParent() == NULL && visible )
  741. {
  742. m_ToolWindowFactory.InstanceToolWindow( this, false, tool, toolName, false );
  743. }
  744. else if ( !visible )
  745. {
  746. ToolWindow *tw = dynamic_cast< ToolWindow * >( tool->GetParent()->GetParent() );
  747. Assert( tw );
  748. tw->RemovePage( tool );
  749. }
  750. }
  751. void CFoundryTool::ToggleToolWindow( Panel *tool, char const *toolName )
  752. {
  753. Assert( tool );
  754. if ( tool->GetParent() == NULL )
  755. {
  756. ShowToolWindow( tool, toolName, true );
  757. }
  758. else
  759. {
  760. ShowToolWindow( tool, toolName, false );
  761. }
  762. }
  763. //-----------------------------------------------------------------------------
  764. // Creates the action menu
  765. //-----------------------------------------------------------------------------
  766. vgui::Menu *CFoundryTool::CreateActionMenu( vgui::Panel *pParent )
  767. {
  768. vgui::Menu *pActionMenu = new Menu( pParent, "ActionMenu" );
  769. pActionMenu->AddMenuItem( "#ToolHide", new KeyValues( "Command", "command", "HideActionMenu" ), GetActionTarget() );
  770. return pActionMenu;
  771. }
  772. //-----------------------------------------------------------------------------
  773. // Inherited from IFileMenuCallbacks
  774. //-----------------------------------------------------------------------------
  775. int CFoundryTool::GetFileMenuItemsEnabled( )
  776. {
  777. int nFlags = FILE_ALL & (~FILE_NEW);
  778. if ( m_RecentFiles.IsEmpty() )
  779. {
  780. nFlags &= ~FILE_RECENT;
  781. }
  782. return nFlags;
  783. }
  784. void CFoundryTool::AddRecentFilesToMenu( vgui::Menu *pMenu )
  785. {
  786. m_RecentFiles.AddToMenu( pMenu, GetActionTarget(), "OnRecent" );
  787. }
  788. bool CFoundryTool::GetPerforceFileName( char *pFileName, int nMaxLen )
  789. {
  790. if ( !m_pMapDoc )
  791. return false;
  792. Q_strncpy( pFileName, GetVMFFileName(), nMaxLen );
  793. return pFileName[0] != 0;
  794. }
  795. //-----------------------------------------------------------------------------
  796. // Purpose:
  797. // Input : -
  798. //-----------------------------------------------------------------------------
  799. void CFoundryTool::OnExit()
  800. {
  801. windowposmgr->SavePositions( "cfg/foundry.txt", "Foundry" );
  802. enginetools->Command( "quit\n" );
  803. }
  804. //-----------------------------------------------------------------------------
  805. // Handle commands from the action menu and other menus
  806. //-----------------------------------------------------------------------------
  807. void CFoundryTool::OnCommand( const char *cmd )
  808. {
  809. if ( !V_stricmp( cmd, "HideActionMenu" ) )
  810. {
  811. if ( GetActionMenu() )
  812. {
  813. GetActionMenu()->SetVisible( false );
  814. }
  815. }
  816. else if ( const char *pSuffix = StringAfterPrefix( cmd, "OnRecent" ) )
  817. {
  818. int idx = Q_atoi( pSuffix );
  819. OpenFileFromHistory( idx );
  820. }
  821. else if ( const char *pSuffix = StringAfterPrefix( cmd, "OnTool" ) )
  822. {
  823. int idx = Q_atoi( pSuffix );
  824. enginetools->SwitchToTool( idx );
  825. }
  826. else if ( !V_stricmp( cmd, "OnUndo" ) )
  827. {
  828. OnUndo();
  829. }
  830. else if ( !V_stricmp( cmd, "OnRedo" ) )
  831. {
  832. OnRedo();
  833. }
  834. else if ( !V_stricmp( cmd, "OnDescribeUndo" ) )
  835. {
  836. OnDescribeUndo();
  837. }
  838. else
  839. {
  840. BaseClass::OnCommand( cmd );
  841. }
  842. }
  843. //-----------------------------------------------------------------------------
  844. // Command handlers
  845. //-----------------------------------------------------------------------------
  846. void CFoundryTool::PerformNew()
  847. {
  848. // Can never do new
  849. Assert( 0 );
  850. }
  851. void CFoundryTool::OnNew()
  852. {
  853. if ( m_pMapDoc )
  854. {
  855. if ( IsDocumentDirty() )
  856. {
  857. SaveFile( GetVMFFileName(), "vmf", FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY,
  858. new KeyValues( "OnNew" ) );
  859. return;
  860. }
  861. }
  862. PerformNew();
  863. }
  864. void CFoundryTool::OnOpen( )
  865. {
  866. int nFlags = 0;
  867. const char *pSaveFileName = NULL;
  868. if ( IsDocumentDirty() )
  869. {
  870. nFlags = FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY;
  871. pSaveFileName = GetVMFFileName();
  872. }
  873. OpenFile( "bsp", pSaveFileName, "vmf", nFlags );
  874. }
  875. bool CFoundryTool::OnReadFileFromDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues )
  876. {
  877. OnCloseNoSave();
  878. if ( !LoadDocument( pFileName ) )
  879. return false;
  880. m_RecentFiles.Add( pFileName, pFileFormat );
  881. m_RecentFiles.SaveToRegistry( GetRegistryName() );
  882. UpdateMenuBar();
  883. return true;
  884. }
  885. void CFoundryTool::OnSave()
  886. {
  887. if ( m_pMapDoc )
  888. {
  889. SaveFile( NULL, "vmf", FOSM_SHOW_PERFORCE_DIALOGS );
  890. }
  891. }
  892. void CFoundryTool::OnSaveAs()
  893. {
  894. if ( m_pMapDoc )
  895. {
  896. SaveFile( GetVMFFileName(), "vmf", FOSM_SHOW_PERFORCE_DIALOGS );
  897. }
  898. }
  899. bool CFoundryTool::OnWriteFileToDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues )
  900. {
  901. if ( !m_pMapDoc )
  902. return true;
  903. m_pMapDoc->SetPathName( pFileName );
  904. m_pMapDoc->SaveVMF( pFileName, 0 );
  905. m_RecentFiles.Add( pFileName, pFileFormat );
  906. m_RecentFiles.SaveToRegistry( GetRegistryName() );
  907. UpdateMenuBar();
  908. return true;
  909. }
  910. void CFoundryTool::OnClose()
  911. {
  912. if ( IsDocumentDirty() )
  913. {
  914. SaveFile( GetVMFFileName(), "vmf", FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY,
  915. new KeyValues( "OnClose" ) );
  916. return;
  917. }
  918. OnCloseNoSave();
  919. }
  920. void CFoundryTool::OnCloseNoSave()
  921. {
  922. }
  923. void CFoundryTool::OnMarkNotDirty()
  924. {
  925. // FIXME: Implement
  926. }
  927. //-----------------------------------------------------------------------------
  928. // Open a specific file
  929. //-----------------------------------------------------------------------------
  930. void CFoundryTool::OpenSpecificFile( const char *pFileName )
  931. {
  932. if ( m_pMapDoc )
  933. {
  934. // TODO: close the MFC document here.
  935. m_pMapDoc = NULL;
  936. }
  937. int nFlags = 0;
  938. const char *pSaveFileName = NULL;
  939. OpenFile( pFileName, "bsp", pSaveFileName, "vmf", nFlags );
  940. }
  941. //-----------------------------------------------------------------------------
  942. // Show the save document query dialog
  943. //-----------------------------------------------------------------------------
  944. void CFoundryTool::OpenFileFromHistory( int slot )
  945. {
  946. const char *pFileName = m_RecentFiles.GetFile( slot );
  947. if ( !pFileName )
  948. return;
  949. OpenSpecificFile( pFileName );
  950. }
  951. //-----------------------------------------------------------------------------
  952. // Derived classes can implement this to get notified when files are saved/loaded
  953. //-----------------------------------------------------------------------------
  954. void CFoundryTool::OnFileOperationCompleted( const char *pFileType, bool bWroteFile, vgui::FileOpenStateMachine::CompletionState_t state, KeyValues *pContextKeyValues )
  955. {
  956. if ( bWroteFile )
  957. {
  958. OnMarkNotDirty();
  959. }
  960. if ( !pContextKeyValues )
  961. return;
  962. if ( state != FileOpenStateMachine::SUCCESSFUL )
  963. return;
  964. if ( !Q_stricmp( pContextKeyValues->GetName(), "OnNew" ) )
  965. {
  966. PerformNew();
  967. return;
  968. }
  969. if ( !Q_stricmp( pContextKeyValues->GetName(), "OnClose" ) )
  970. {
  971. OnCloseNoSave();
  972. return;
  973. }
  974. if ( !Q_stricmp( pContextKeyValues->GetName(), "OnQuit" ) )
  975. {
  976. OnCloseNoSave();
  977. vgui::ivgui()->PostMessage( GetVPanel(), new KeyValues( "OnExit" ), 0 );
  978. return;
  979. }
  980. if ( !Q_stricmp( pContextKeyValues->GetName(), "OnUnload" ) )
  981. {
  982. enginetools->Command( "toolunload foundry -nosave\n" );
  983. return;
  984. }
  985. }
  986. //-----------------------------------------------------------------------------
  987. // Show the File browser dialog
  988. //-----------------------------------------------------------------------------
  989. void CFoundryTool::SetupFileOpenDialog( vgui::FileOpenDialog *pDialog, bool bOpenFile, const char *pFileFormat, KeyValues *pContextKeyValues )
  990. {
  991. char pStartingDir[ MAX_PATH ];
  992. // We open BSPs, but save-as VMFs
  993. if ( bOpenFile )
  994. {
  995. GetModSubdirectory( "maps", pStartingDir, sizeof(pStartingDir) );
  996. pDialog->SetTitle( "Choose Valve BSP File", true );
  997. pDialog->SetStartDirectoryContext( "foundry_bsp_session", pStartingDir );
  998. pDialog->AddFilter( "*.bsp", "Valve BSP File (*.bsp)", true );
  999. }
  1000. else
  1001. {
  1002. GetModContentSubdirectory( "maps", pStartingDir, sizeof(pStartingDir) );
  1003. pDialog->SetTitle( "Choose Valve VMF File", true );
  1004. pDialog->SetStartDirectoryContext( "foundry_vmf_session", pStartingDir );
  1005. pDialog->AddFilter( "*.vmf", "Valve VMF File (*.vmf)", true );
  1006. }
  1007. }
  1008. //-----------------------------------------------------------------------------
  1009. // Can we quit?
  1010. //-----------------------------------------------------------------------------
  1011. bool CFoundryTool::CanQuit( const char *pExitMsg )
  1012. {
  1013. if ( IsDocumentDirty() )
  1014. {
  1015. // Show Save changes Yes/No/Cancel and re-quit if hit yes/no
  1016. SaveFile( GetVMFFileName(), "vmf", FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY, new KeyValues( pExitMsg ) );
  1017. return false;
  1018. }
  1019. return true;
  1020. }
  1021. //-----------------------------------------------------------------------------
  1022. // Various command handlers related to the Edit menu
  1023. //-----------------------------------------------------------------------------
  1024. void CFoundryTool::OnUndo()
  1025. {
  1026. CDisableUndoScopeGuard guard;
  1027. g_pDataModel->Undo();
  1028. }
  1029. void CFoundryTool::OnRedo()
  1030. {
  1031. CDisableUndoScopeGuard guard;
  1032. g_pDataModel->Redo();
  1033. }
  1034. void CFoundryTool::OnDescribeUndo()
  1035. {
  1036. CUtlVector< UndoInfo_t > list;
  1037. g_pDataModel->GetUndoInfo( list );
  1038. Msg( "%i operations in stack\n", list.Count() );
  1039. for ( int i = list.Count() - 1; i >= 0; --i )
  1040. {
  1041. UndoInfo_t& entry = list[ i ];
  1042. if ( entry.terminator )
  1043. {
  1044. Msg( "[ '%s' ] - %i operations\n", entry.undo, entry.numoperations );
  1045. }
  1046. Msg( " +%s\n", entry.desc );
  1047. }
  1048. }
  1049. //-----------------------------------------------------------------------------
  1050. // Foundry menu items
  1051. //-----------------------------------------------------------------------------
  1052. void CFoundryTool::OnReload()
  1053. {
  1054. // Reloads the map, entities only, will reload every entity
  1055. enginetools->Command( "respawn_entities\n" );
  1056. }
  1057. void CFoundryTool::OnReloadFromSave()
  1058. {
  1059. // Reloads the map from a save point, overrides selected entities
  1060. // for now, this is hardcoded to be info_targets
  1061. enginetools->Command( "load quick\n" );
  1062. }
  1063. void CFoundryTool::OnUpdateHammerEntity()
  1064. {
  1065. enginetools->Command( "foundry_update_entity" );
  1066. }
  1067. void CFoundryTool::OnReloadFromSaveSlamEnts()
  1068. {
  1069. m_SavegameRestoredEnts.Purge();
  1070. enginetools->Command( "load quick * LetToolsOverrideLoadGameEnts\n" );
  1071. enginetools->Execute();
  1072. }
  1073. //-----------------------------------------------------------------------------
  1074. // Background
  1075. //-----------------------------------------------------------------------------
  1076. const char *CFoundryTool::GetLogoTextureName()
  1077. {
  1078. //return "vgui/tools/sampletool/sampletool_logo";
  1079. return NULL;
  1080. }
  1081. //-----------------------------------------------------------------------------
  1082. // Inherited from IFoundryDocCallback
  1083. //-----------------------------------------------------------------------------
  1084. void CFoundryTool::OnDocChanged( const char *pReason, int nNotifySource, int nNotifyFlags )
  1085. {
  1086. UpdateMenuBar();
  1087. /*
  1088. if ( bRefreshUI && m_hProperties.Get() )
  1089. {
  1090. m_hProperties->Refresh();
  1091. }
  1092. */
  1093. }
  1094. //-----------------------------------------------------------------------------
  1095. // List of all entity classnames to copy over from the original block
  1096. //-----------------------------------------------------------------------------
  1097. static const char *s_pUseOriginalClasses[] =
  1098. {
  1099. "worldspawn",
  1100. "func_occluder",
  1101. NULL
  1102. };
  1103. //-----------------------------------------------------------------------------
  1104. // Always copy the worldspawn and other entities that had data built into them by VBSP out
  1105. //-----------------------------------------------------------------------------
  1106. void CFoundryTool::AddOriginalEntities( CUtlBuffer &entityBuf, const char *pActualEntityData )
  1107. {
  1108. while ( *pActualEntityData )
  1109. {
  1110. pActualEntityData = strchr( pActualEntityData, '{' );
  1111. if ( !pActualEntityData )
  1112. break;
  1113. const char *pBlockStart = pActualEntityData;
  1114. pActualEntityData = strstr( pActualEntityData, "\"classname\"" );
  1115. if ( !pActualEntityData )
  1116. break;
  1117. // Skip "classname"
  1118. pActualEntityData += 11;
  1119. pActualEntityData = strchr( pActualEntityData, '\"' );
  1120. if ( !pActualEntityData )
  1121. break;
  1122. // Skip "
  1123. ++pActualEntityData;
  1124. char pClassName[512];
  1125. int j = 0;
  1126. while (*pActualEntityData != 0 && *pActualEntityData != '\"' )
  1127. {
  1128. pClassName[j++] = *pActualEntityData++;
  1129. }
  1130. pClassName[j] = 0;
  1131. pActualEntityData = strchr( pActualEntityData, '}' );
  1132. if ( !pActualEntityData )
  1133. break;
  1134. // Skip }
  1135. ++pActualEntityData;
  1136. for ( int i = 0; s_pUseOriginalClasses[i]; ++i )
  1137. {
  1138. if ( !Q_stricmp( pClassName, s_pUseOriginalClasses[i] ) )
  1139. {
  1140. // Found one we need to keep, add it to the buffer
  1141. int nBytes = (int)( (size_t)pActualEntityData - (size_t)pBlockStart );
  1142. entityBuf.Put( pBlockStart, nBytes );
  1143. entityBuf.PutChar( '\n' );
  1144. break;
  1145. }
  1146. }
  1147. }
  1148. }
  1149. //-----------------------------------------------------------------------------
  1150. // Copy in other entities from the editable VMF
  1151. //-----------------------------------------------------------------------------
  1152. void CFoundryTool::AddVMFEntities( CUtlBuffer &entityBuf, const char *pActualEntityData )
  1153. {
  1154. }
  1155. bool CFoundryTool::IsDocumentDirty()
  1156. {
  1157. return m_pMapDoc && m_pMapDoc->IsModified();
  1158. }
  1159. //-----------------------------------------------------------------------------
  1160. // Create a text block the engine can parse containing the entity data to spawn
  1161. //-----------------------------------------------------------------------------
  1162. const char* CFoundryTool::GenerateEntityData( const char *pActualEntityData )
  1163. {
  1164. return pActualEntityData;
  1165. }
  1166. const char* CFoundryTool::GetVMFFileName()
  1167. {
  1168. if ( m_pMapDoc )
  1169. return m_pMapDoc->GetPathName();
  1170. else
  1171. return "";
  1172. }
  1173. //-----------------------------------------------------------------------------
  1174. // Loads up a new document
  1175. //-----------------------------------------------------------------------------
  1176. bool CFoundryTool::LoadDocument( const char *pFileName )
  1177. {
  1178. Assert( !m_pMapDoc );
  1179. DestroyTools();
  1180. // Store the BSP file name
  1181. Q_strncpy( m_pBSPFileName, pFileName, sizeof( m_pBSPFileName ) );
  1182. // Construct VMF file name from the BSP
  1183. const char *pGame = Q_stristr( pFileName, "\\game\\" );
  1184. if ( !pGame )
  1185. return false;
  1186. // Compute the map name
  1187. char mapname[ 256 ];
  1188. const char *pMaps = Q_stristr( pFileName, "\\maps\\" );
  1189. if ( !pMaps )
  1190. return false;
  1191. Q_strncpy( mapname, pMaps + 6, sizeof( mapname ) );
  1192. int nLen = (int)( (size_t)pGame - (size_t)pFileName ) + 1;
  1193. char vmfFilename[MAX_PATH];
  1194. Q_strncpy( vmfFilename, pFileName, nLen );
  1195. Q_strncat( vmfFilename, "\\content\\", sizeof(vmfFilename) );
  1196. Q_strncat( vmfFilename, pGame + 6, sizeof(vmfFilename) );
  1197. Q_SetExtension( vmfFilename, ".vmf", sizeof(vmfFilename) );
  1198. // Have Hammer load this VMF.
  1199. CHammer *pApp = (CHammer*) AfxGetApp();
  1200. m_pMapDoc = (CMapDoc*)pApp->pMapDocTemplate->OpenDocumentFile( vmfFilename );
  1201. // Now have the engine load the map.
  1202. char cmd[ 256 ];
  1203. Q_snprintf( cmd, sizeof( cmd ), "disconnect; map %s\n", mapname );
  1204. enginetools->Command( cmd );
  1205. enginetools->Execute( );
  1206. ShowMiniViewport( true );
  1207. CreateTools();
  1208. InitTools();
  1209. return true;
  1210. }
  1211. //-----------------------------------------------------------------------------
  1212. // Create the entities that are in our VMF file
  1213. //-----------------------------------------------------------------------------
  1214. void* CFoundryTool::QueryInterface( const char *pInterfaceName )
  1215. {
  1216. if ( V_stricmp( pInterfaceName, VSERVERFOUNDRY_INTERFACE_VERSION ) == 0 )
  1217. return (IServerFoundry*)this;
  1218. return NULL;
  1219. }
  1220. // This simulates passing entity data through VBSP. We should share the code with VBSP here if the format changes
  1221. // and this gets complicated, but it would involve lots of ugly #ifdef HAMMER's chopping up map.cpp.
  1222. static bool TransformEntityVMFToBSPFormat( char *pIn, CUtlVector<char> &data )
  1223. {
  1224. ParseFromMemory( pIn, V_strlen( pIn ) );
  1225. // Ignore the leading "entity {"
  1226. // Also ignore everything inside "editor"
  1227. if ( !GetToken(true) || V_stricmp(token, "entity") != 0 || !GetToken(true) || V_stricmp(token,"{") != 0 )
  1228. {
  1229. Warning( "Unknown entity format.\n" );
  1230. return false;
  1231. }
  1232. bool bInsideEditorBlock = false;
  1233. bool bValidFile = false;
  1234. int braceLevel = 1;
  1235. while ( 1 )
  1236. {
  1237. char firstToken[MAXTOKEN];
  1238. GetToken( true );
  1239. V_strncpy( firstToken, token, sizeof( firstToken ) );
  1240. if ( firstToken[0] == '}' )
  1241. {
  1242. --braceLevel;
  1243. if ( braceLevel == 0 )
  1244. {
  1245. // If we end the file and we're not somehow in the editor block, then the file is good.
  1246. bValidFile = !bInsideEditorBlock;
  1247. break;
  1248. }
  1249. else
  1250. {
  1251. bInsideEditorBlock = false;
  1252. }
  1253. continue;
  1254. }
  1255. if ( !GetToken( true ) )
  1256. break;
  1257. if ( token[0] == '{' )
  1258. {
  1259. ++braceLevel;
  1260. if ( V_stricmp( firstToken, "editor" ) == 0 )
  1261. bInsideEditorBlock = true;
  1262. continue;
  1263. }
  1264. if ( bInsideEditorBlock )
  1265. continue;
  1266. char outStr[MAXTOKEN*2+16];
  1267. V_snprintf( outStr, sizeof( outStr ), "\"%s\" \"%s\"\n", firstToken, token );
  1268. data.AddMultipleToTail( V_strlen( outStr ), outStr );
  1269. }
  1270. if ( !bValidFile )
  1271. {
  1272. Warning( "Invalid entity format.\n" );
  1273. return false;
  1274. }
  1275. data.AddToTail( '}' );
  1276. data.AddToTail( 0 ); // Null-terminate our string.
  1277. return true;
  1278. }
  1279. static bool LoadFileDataIntoBuffer( const char *pFilename, const char *pFormat, CUtlVector<char> &tempData )
  1280. {
  1281. FILE *fp = fopen( pFilename, pFormat );
  1282. if ( !fp )
  1283. {
  1284. return false;
  1285. }
  1286. fseek( fp, 0, SEEK_END );
  1287. tempData.SetSize( ftell( fp ) + 1 );
  1288. fseek( fp, 0, SEEK_SET );
  1289. fread( tempData.Base(), 1, tempData.Count()-1, fp );
  1290. fclose( fp );
  1291. return true;
  1292. }
  1293. bool CFoundryTool::GetEntityVMFText( CMapClass *pClass, CUtlVector<char> &data )
  1294. {
  1295. char baseDir[MAX_PATH], cheesyFilename[MAX_PATH];
  1296. _getcwd( baseDir, sizeof( baseDir ) );
  1297. V_ComposeFileName( baseDir, "__foundry_tempchunk.txt", cheesyFilename, sizeof( cheesyFilename ) );
  1298. // Save this entity's data into a temporary file.
  1299. CSaveInfo saveInfo;
  1300. saveInfo.SetVisiblesOnly( false );
  1301. CChunkFile chunkFile;
  1302. chunkFile.Open( cheesyFilename, ChunkFile_Write );
  1303. ChunkFileResult_t result = pClass->SaveVMF( &chunkFile, &saveInfo );
  1304. chunkFile.Close();
  1305. if ( result != ChunkFile_Ok )
  1306. {
  1307. return false;
  1308. }
  1309. // Load the temporary file into memory.
  1310. CUtlVector<char> tempData;
  1311. if ( !LoadFileDataIntoBuffer( cheesyFilename, "rt", tempData ) )
  1312. {
  1313. Warning( "Internal error in GetEntityVMFText\n" );
  1314. return false;
  1315. }
  1316. DeleteFile( cheesyFilename );
  1317. // Convert from the VMF-format entity to the BSP-format entity.
  1318. return TransformEntityVMFToBSPFormat( tempData.Base(), data );
  1319. }
  1320. bool CFoundryTool::GetRestoredEntityReplacementData( int iHammerID, CUtlVector<char> &data )
  1321. {
  1322. CMapDoc *pDoc = g_pFoundryToolImp->GetDocument();
  1323. CSelection *pSelection = pDoc->GetSelection();
  1324. if ( !pSelection || pSelection->IsEmpty() )
  1325. return false;
  1326. const CMapObjectList *pObjectList = pSelection->GetList();
  1327. for ( int i=0; i < pObjectList->Count(); i++ )
  1328. {
  1329. CMapClass *pClass = (CUtlReference< CMapClass >)pObjectList->Element( i );
  1330. if ( pClass->GetID() == iHammerID )
  1331. {
  1332. if ( GetEntityVMFText( pClass, data ) )
  1333. {
  1334. m_SavegameRestoredEnts.AddToTail( pClass->GetID() );
  1335. return true;
  1336. }
  1337. else
  1338. {
  1339. return false;
  1340. }
  1341. }
  1342. }
  1343. return false;
  1344. }
  1345. void CFoundryTool::OnFinishedRestoreSavegame()
  1346. {
  1347. CUtlVector<CMapClass*> toRespawn;
  1348. // We're restoring a savegame and slamming any ents that are selected.
  1349. // The savegame is finished, so now slam entities that are selected but weren't in the savegame.
  1350. CMapDoc *pDoc = g_pFoundryToolImp->GetDocument();
  1351. CSelection *pSelection = pDoc->GetSelection();
  1352. if ( pSelection && !pSelection->IsEmpty() )
  1353. {
  1354. const CMapObjectList *pObjectList = pSelection->GetList();
  1355. for ( int i=0; i < pObjectList->Count(); i++ )
  1356. {
  1357. CMapClass *pClass = (CUtlReference< CMapClass >)pObjectList->Element( i );
  1358. if ( m_SavegameRestoredEnts.Find( pClass->GetID() ) == -1 )
  1359. {
  1360. toRespawn.AddToTail( pClass );
  1361. }
  1362. }
  1363. }
  1364. RespawnEntitiesWithEdits( toRespawn.Base(), toRespawn.Count() );
  1365. m_SavegameRestoredEnts.Purge();
  1366. }
  1367. void CFoundryTool::MoveEntityTo( int nHammerID, const Vector &vPos, const QAngle &vAngles )
  1368. {
  1369. CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
  1370. if ( !pDoc )
  1371. {
  1372. Warning( "CFoundryTool::MoveEntityTo - no active CMapDoc\n" );
  1373. return;
  1374. }
  1375. //
  1376. CMapEntity *pEnt = pDoc->FindEntityByHammerID( nHammerID );
  1377. if ( !pEnt )
  1378. {
  1379. Warning( "CFoundryTool::MoveEntityTo - no entity with HammerID %d\n", nHammerID );
  1380. return;
  1381. }
  1382. Vector vTempPos = vPos;
  1383. pEnt->SetOrigin( vTempPos );
  1384. CEditGameClass *pClass = dynamic_cast< CEditGameClass * >( pEnt );
  1385. if ( pClass )
  1386. pClass->SetAngles( vAngles );
  1387. }
  1388. void CFoundryTool::ClientPostRender()
  1389. {
  1390. if ( !m_pMapDoc || !foundry_draw_hammer_entities.GetBool() )
  1391. return;
  1392. CMapView3D *pView = m_pMapDoc->GetFirst3DView();
  1393. if ( !pView )
  1394. return;
  1395. // Store the old camera view parameters.
  1396. CCamera *pCamera = pView->GetCamera();
  1397. float flOldPitch = pCamera->GetPitch();
  1398. float flOldYaw = pCamera->GetYaw();
  1399. Vector vOldViewPoint;
  1400. pCamera->GetViewPoint( vOldViewPoint );
  1401. float flOldFOV = pCamera->GetFOV();
  1402. float flOldNearClip = pCamera->GetNearClip();
  1403. float flOldFarClip = pCamera->GetFarClip();
  1404. // Move the Hammer camera to the engine's position for rendering.
  1405. Vector vForward;
  1406. AngleVectors( m_v3dViewAngles, &vForward );
  1407. pView->SetCamera( m_v3dViewOrigin, m_v3dViewOrigin + vForward * 100 );
  1408. pView->RenderView2( true );
  1409. // Restore the old camera view parameters.
  1410. pCamera->SetViewPoint( vOldViewPoint );
  1411. pCamera->SetPerspective( flOldFOV, flOldNearClip, flOldFarClip );
  1412. pCamera->SetPitch( flOldPitch );
  1413. pCamera->SetYaw( flOldYaw );
  1414. }
  1415. bool CFoundryTool::SetupEngineView( Vector &origin, QAngle &angles, float &fov )
  1416. {
  1417. m_v3dViewOrigin = origin;
  1418. m_v3dViewAngles = angles;
  1419. m_fl3dViewFOV = fov;
  1420. return BaseClass::SetupEngineView( origin, angles, fov );
  1421. }
  1422. bool CFoundryTool::TrapKey( ButtonCode_t key, bool down )
  1423. {
  1424. return BaseClass::TrapKey( key, down );
  1425. }
  1426. bool CFoundryTool::UpdateEntity( int iHammerID, CUtlVector<char*> &keys, CUtlVector<char*> &values )
  1427. {
  1428. // Find the entity to be updated
  1429. void *pServerEntity = servertools->FindEntityByHammerID( iHammerID );
  1430. if ( pServerEntity != NULL)
  1431. {
  1432. // Set updated properties
  1433. for ( int i = 0; i < keys.Count(); i++ )
  1434. {
  1435. servertools->SetKeyValue( pServerEntity, keys[i], values[i] );
  1436. }
  1437. return true;
  1438. }
  1439. // Entity not found in running game
  1440. return false;
  1441. }
  1442. void CFoundryTool::RespawnEntitiesWithEdits( CMapClass **ppEntities, int nEntities )
  1443. {
  1444. CUtlVector<char> *pDatas = new CUtlVector<char>[nEntities];
  1445. CUtlVector<CEntityRespawnInfo> respawnInfos;
  1446. respawnInfos.SetSize( nEntities );
  1447. int nValid = 0;
  1448. for ( int i=0; i < nEntities; i++ )
  1449. {
  1450. if ( GetEntityVMFText( ppEntities[i], pDatas[nValid] ) )
  1451. {
  1452. respawnInfos[nValid].m_nHammerID = ppEntities[i]->GetHammerID();
  1453. respawnInfos[nValid].m_pEntText = pDatas[nValid].Base();
  1454. ++nValid;
  1455. }
  1456. }
  1457. servertools->RespawnEntitiesWithEdits( respawnInfos.Base(), nValid );
  1458. delete [] pDatas;
  1459. }
  1460. void CFoundryTool::DestroyEntity( int iHammerID )
  1461. {
  1462. servertools->DestroyEntityByHammerId( iHammerID );
  1463. }
  1464. void CFoundryTool::OnModeChanged()
  1465. {
  1466. BaseClass::OnModeChanged();
  1467. // We can get here during shutdown.
  1468. if ( !GetMainWnd() )
  1469. return;
  1470. if ( IsGameInputEnabled() )
  1471. {
  1472. GetMainWnd()->EnableWindow( false );
  1473. // Unpause the game.
  1474. if ( foundry_auto_pause.GetInt() == 1 )
  1475. enginetools->Command( "unpause" );
  1476. else if ( foundry_auto_pause.GetInt() == 2 )
  1477. enginetools->Command( "ai_setenabled 1" );
  1478. }
  1479. else
  1480. {
  1481. GetMainWnd()->EnableWindow( true );
  1482. // Pause the game.
  1483. if ( foundry_auto_pause.GetInt() == 1 )
  1484. enginetools->Command( "setpause" );
  1485. else if ( foundry_auto_pause.GetInt() == 2 )
  1486. enginetools->Command( "ai_setenabled 0" );
  1487. }
  1488. }
  1489. void CFoundryTool::SwitchToEngine()
  1490. {
  1491. EngineGetMouseControl();
  1492. }
  1493. void CFoundryTool::MoveEngineViewTo( const Vector &vPos, const QAngle &vAngles )
  1494. {
  1495. servertools->MoveEngineViewTo( vPos, vAngles );
  1496. }
  1497. void CFoundryTool::MoveHammerViewTo( const Vector &vPos, const QAngle &vAngles )
  1498. {
  1499. CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
  1500. if ( !pDoc )
  1501. return;
  1502. POSITION p = pDoc->GetFirstViewPosition();
  1503. while (p != NULL)
  1504. {
  1505. CMapView3D *pView = dynamic_cast< CMapView3D* >( pDoc->GetNextView(p) );
  1506. if ( pView )
  1507. {
  1508. CCamera *pCamera = pView->GetCamera();
  1509. pCamera->SetViewPoint( vPos );
  1510. pCamera->SetPitch( vAngles[PITCH] );
  1511. pCamera->SetYaw( -vAngles[YAW] + 90.0f );
  1512. pCamera->SetRoll( 0 );
  1513. return;
  1514. }
  1515. }
  1516. }
  1517. void CFoundryTool::EngineGetMouseControl()
  1518. {
  1519. // Set focus on the engine window.
  1520. ::SetFocus( (HWND)enginetools->GetEngineHwnd() );
  1521. SetMode( true, false );
  1522. }
  1523. void CFoundryTool::EngineReleaseMouseControl()
  1524. {
  1525. SetMode( false, false );
  1526. }
  1527. void CFoundryTool::SelectEntities( int *pHammerIDs, int nIDs )
  1528. {
  1529. CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
  1530. if ( !pDoc )
  1531. return;
  1532. pDoc->ClearEntitySelection();
  1533. for ( int i=0; i < nIDs; i++ )
  1534. {
  1535. CMapEntity *pEnt = pDoc->FindEntityByHammerID( pHammerIDs[i] );
  1536. pDoc->SelectObject( pEnt, scSelect );
  1537. }
  1538. }
  1539. void CFoundryTool::ConsoleCommand( const char *pConCommand )
  1540. {
  1541. enginetools->Command( pConCommand );
  1542. }
  1543. bool CFoundryTool::ShouldRender3DModels()
  1544. {
  1545. return foundry_draw_hammer_models.GetBool();
  1546. }
  1547. void CFoundryTool::SelectionClickInCenterOfView( const Vector &vPos, const QAngle &vAngles )
  1548. {
  1549. // First move the camera
  1550. CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
  1551. if ( !pDoc )
  1552. return;
  1553. CMapView3D *pView = NULL;
  1554. POSITION p = pDoc->GetFirstViewPosition();
  1555. while (p != NULL)
  1556. {
  1557. pView = dynamic_cast< CMapView3D* >( pDoc->GetNextView(p) );
  1558. if ( pView )
  1559. break;
  1560. }
  1561. if ( !pView )
  1562. return;
  1563. CToolManager *pToolManager = pDoc->GetTools();
  1564. pToolManager->SetTool( TOOL_POINTER );
  1565. CBaseTool *pTool = pToolManager->GetActiveTool();
  1566. if ( !pTool )
  1567. return;
  1568. // Setup the camera position.
  1569. CCamera *pCamera = pView->GetCamera();
  1570. CCamera cameraBackup = *pCamera;
  1571. pCamera->SetViewPoint( vPos );
  1572. pCamera->SetPitch( vAngles[PITCH] );
  1573. pCamera->SetYaw( -vAngles[YAW] + 90.0f );
  1574. pCamera->SetRoll( 0 );
  1575. RECT rc;
  1576. pView->GetClientRect( &rc );
  1577. // Simulate a mouse click.
  1578. Vector2D vPoint( (rc.right - rc.left) / 2, (rc.bottom - rc.top) / 2 );
  1579. pTool->OnLMouseDown3D( pView, 0, vPoint );
  1580. pTool->OnLMouseUp3D( pView, 0, vPoint );
  1581. // Restore the camera.
  1582. *pCamera = cameraBackup;
  1583. }
  1584. // Called by the engine when exiting.
  1585. bool CFoundryTool::StaticQuitHandler( void *pvUserData )
  1586. {
  1587. AFX_MANAGE_STATE(AfxGetStaticModuleState())
  1588. CMainFrame *pFrame = GetMainWnd();
  1589. if ( pFrame )
  1590. pFrame->PostMessageA( WM_CLOSE, 0, 0 );
  1591. // Return false to tell the engine to ignore the quit request. If Hammer finishes up the WM_QUIT, then everything will shutdown properly.
  1592. return false;
  1593. }
  1594. void CFoundryTool::OnMapDocDestroy( CMapDoc *pDoc )
  1595. {
  1596. if ( m_pMapDoc == pDoc )
  1597. m_pMapDoc = NULL;
  1598. }