/* ** Command & Conquer Renegade(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ /*********************************************************************************************** *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** *********************************************************************************************** * * * Project Name : LevelEdit * * * * $Archive:: /Commando/Code/Tools/LevelEdit/FileMgr.cpp $* * * * Author:: Patrick Smith * * * * $Modtime:: 1/29/02 2:59p $* * * * $Revision:: 36 $* * * *---------------------------------------------------------------------------------------------* * Functions: * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #include "stdafx.h" #include "filemgr.h" #include "utils.h" #include "rendobj.h" #include "matinfo.h" #include "regkeys.h" #include "leveledit.h" #include "_assetmgr.h" #include "editorassetmgr.h" #include "updatingdbdialog.h" #include "uniquelist.h" #include "part_emt.h" #include "filelocations.h" #include "editorini.h" #include "ffactory.h" #include "ww3d.h" #include "node.h" #include "preset.h" #include "presetmgr.h" #include "spawnernode.h" #include "wwstring.h" #include "vssclass.h" #include "assetdatabase.h" #include "editorbuild.h" #include "assetpackagemgr.h" #include "mixfiledatabase.h" //////////////////////////////////////////////////////////////////////// // Constants //////////////////////////////////////////////////////////////////////// const char *SPECIAL_USER_NAME = "Artist"; const char *SPECIAL_USER_FOLDER = ""; const char *PROXY_TESTS_FOLDER = ""; //////////////////////////////////////////////////////////////////////// // Static member initialization //////////////////////////////////////////////////////////////////////// bool FileMgrClass::_bAutoUpdateOn = false; //////////////////////////////////////////////////////////////////////// // // FileMgrClass // //////////////////////////////////////////////////////////////////////// FileMgrClass::FileMgrClass (void) : m_bVSSInitialized (false), m_bReadOnlyVSS (true), m_IsSpecialUser (false) { #ifdef PUBLIC_EDITOR_VER // // Allocate the database interface layer we'll need to access assets // m_DatabaseInterface = new MixFileDatabaseClass; // // Get the asset directory from the asset package manager // m_BasePath = AssetPackageMgrClass::Get_Current_Package_Path (); #else // // Allocate the database interface layer we'll need to access assets // m_DatabaseInterface = new VSSClass; // // Read the asset directory from the registry // m_BasePath = theApp.GetProfileString (CONFIG_KEY, ASSET_DIR_VALUE); #endif //PUBLIC_EDITOR_VER // // Ensure the base has a directory delimiter on the end // if ((m_BasePath.GetLength () > 0) && m_BasePath[::lstrlen (m_BasePath) - 1] != '\\') { m_BasePath += "\\"; } // // The new cache directory is simply a subdirectory of the base // m_TextureCachePath = m_BasePath + "EditorCache"; if (::GetFileAttributes (m_TextureCachePath) == 0xFFFFFFFF) { ::CreateDirectory (m_TextureCachePath, NULL); } return ; } //////////////////////////////////////////////////////////////////////// // // Initialize // //////////////////////////////////////////////////////////////////////// void FileMgrClass::Initialize (void) { Free_Data (); return ; } //////////////////////////////////////////////////////////////////////// // // Free_Data // //////////////////////////////////////////////////////////////////////// void FileMgrClass::Free_Data (void) { // Loop through all the files in our array for (int index = 0; index < m_FileList.Count (); index ++) { // Free this entry LevelFileStruct *pentry = m_FileList[index]; SAFE_DELETE (pentry); } // Remove all the entries from our list. m_FileList.Delete_All (); return ; } //////////////////////////////////////////////////////////////////////// // // Make_Full_Path // //////////////////////////////////////////////////////////////////////// CString FileMgrClass::Make_Full_Path (LPCTSTR rel_path) { CString full_path = rel_path; // Is this path really relative? if (::Is_Path_Relative (rel_path)) { // Strip of the preceding directory delimiter if there is one. if ((full_path.GetLength () > 0) && (full_path[0] == '\\')) { full_path = &(((LPCTSTR)full_path)[1]); } // Return the full path full_path = m_BasePath + rel_path; // Strip off the last delimiter if necessary if (full_path[::lstrlen (full_path) - 1] == '\\') { full_path = full_path.Left (full_path.GetLength () - 1); } } // Return a string which contains the full path to the data file return full_path; } //////////////////////////////////////////////////////////////////////// // // Make_Relative_Path // //////////////////////////////////////////////////////////////////////// CString FileMgrClass::Make_Relative_Path (LPCTSTR full_path) { CString base_path = m_BasePath; CString lower_path = full_path; lower_path.MakeLower (); base_path.MakeLower (); LPCTSTR rel_path = lower_path; // Is our 'base' part of the full path? if (::strstr (rel_path, base_path) == rel_path) { // The relative path is the full path minus the base path rel_path += m_BasePath.GetLength (); // Strip of the preceding directory delimiter if there is one. if (rel_path[0] == '\\') { rel_path = &(((LPCTSTR)rel_path)[1]); } } // Return a string which contains the relative path to the data file return CString (rel_path); } //////////////////////////////////////////////////////////////////////// // // Is_Empty_Path // //////////////////////////////////////////////////////////////////////// bool FileMgrClass::Is_Empty_Path (LPCTSTR path) { bool retval = true; if (path[0] != 0) { CString temp1 = path; CString temp2 = m_BasePath; ::Delimit_Path (temp1); ::Delimit_Path (temp2); retval = bool(::stricmp (temp1, temp2) == 0); } return retval; } //////////////////////////////////////////////////////////////////////// // // Is_Path_Valid // //////////////////////////////////////////////////////////////////////// bool FileMgrClass::Is_Path_Valid (LPCTSTR path) { // The path is valid if its located under the asset tree return bool(::strnicmp (path, m_BasePath, m_BasePath.GetLength ()) == 0); } //////////////////////////////////////////////////////////////////////// // // Is_Path_In_Asset_Tree // //////////////////////////////////////////////////////////////////////// bool FileMgrClass::Is_Path_In_Asset_Tree (LPCTSTR path) { CString full_path = Make_Full_Path (path); return bool(::strnicmp (full_path, m_BasePath, m_BasePath.GetLength ()) == 0); } //////////////////////////////////////////////////////////////////////// // // Does_File_Exist // //////////////////////////////////////////////////////////////////////// bool FileMgrClass::Does_File_Exist ( LPCTSTR filename, bool update_from_vss ) { // Assume it doesn't exist bool file_exists = false; // Param valid? ASSERT (filename != NULL); if (filename != NULL) { // Ensure the path is complete CString path = Make_Full_Path (filename); file_exists = bool(::GetFileAttributes (path) != 0xFFFFFFFF); #ifndef PUBLIC_EDITOR_VER // // Should we try to get this file from VSS? // if (update_from_vss && (file_exists == false)) { // // If the file is in VSS, then get it and return the success code // if (Is_File_In_VSS (path)) { file_exists = Update_File (path); } } #endif //!PUBLIC_EDITOR_VER } // Return the true/false result code return file_exists; } ///////////////////////////////////////////////////////////////// // // Find_File // ///////////////////////////////////////////////////////////////// int FileMgrClass::Find_File (LPCTSTR filename) const { // Assume failure int index = -1; // Can we add another property to our list? ASSERT (filename != NULL); if (filename != NULL) { // Loop through all the files in our array for (int file_index = 0; (file_index < m_FileList.Count ()) && (index == -1); file_index ++) { // Was this the file we were looking for? if (::lstrcmpi (m_FileList[file_index]->m_Filename, filename) == 0) { index = file_index; } } } // Return the file's index (-1) on error return index; } ///////////////////////////////////////////////////////////////// // // Remove_File // ///////////////////////////////////////////////////////////////// bool FileMgrClass::Remove_File (int index) { // Assume failure bool retval = false; // Param valid? if ((index >= 0) && (index < m_FileList.Count ())) { // Decrement the ref count on this entry LevelFileStruct *pentry = m_FileList[index]; pentry->m_RefCount --; // Do we need to remove this item from the list? if (pentry->m_RefCount == 0) { // Free the memory used by this entry and remove it // from the list SAFE_DELETE (pentry); m_FileList.Delete (index); } // Success! retval = true; } // Return the true/false result code return retval; } ///////////////////////////////////////////////////////////////// // // Add_Files_To_Database // ///////////////////////////////////////////////////////////////// bool FileMgrClass::Add_Files_To_Database (LPCTSTR filename) { // Assume success //bool retval = true; ASSERT (filename != NULL); m_CurrentFile = filename; Add_Files_To_Database (); // Return the true/false success code return true; } ///////////////////////////////////////////////////////////////// // // Add_File_To_Database // ///////////////////////////////////////////////////////////////// bool FileMgrClass::Add_File_To_Database (LPCTSTR filename) { CString path = Make_Full_Path (filename); if (Does_File_Exist (path) && (m_DatabaseInterface->Does_File_Exist (path) == false)) { m_DatabaseInterface->Add_File (path); } return true; } ///////////////////////////////////////////////////////////////// // // Add_Files_To_Database // ///////////////////////////////////////////////////////////////// void FileMgrClass::Add_Files_To_Database (void) { // Build a unique list of dependencies on this W3D file UniqueListClass unique_list; // // If this is a W3D model, enumerate its dependencies, otherwise // just add it to the list // if (::Is_W3D_Filename (m_CurrentFile)) { Build_Dependency_List (m_CurrentFile, unique_list); } else { unique_list.Add (Make_Full_Path (m_CurrentFile)); } CString current_dir = ::Strip_Filename_From_Path (m_CurrentFile); current_dir = Make_Full_Path (current_dir); // // Now loop through all the files in the unique list and // add them to VSS. // for (int index = 0; index < unique_list.Count (); index ++) { CString full_path = unique_list[index]; // // Does this file live outside of our asset tree? // if (Is_Path_In_Asset_Tree (full_path) == false) { CString filename = ::Get_Filename_From_Path (full_path); CString local_path = ::Make_Path (current_dir, filename); // // Copy the file to the asset tree // if (::Quick_Compare_Files (full_path, local_path) != 0) { ::Copy_File (full_path, local_path, FALSE); } full_path = local_path; } // // Add this file to VSS (if needs be) // if (Does_File_Exist (full_path) && (m_DatabaseInterface->Does_File_Exist (full_path) == false)) { m_DatabaseInterface->Add_File (full_path); } } return ; } ///////////////////////////////////////////////////////////////// // // Add_File // ///////////////////////////////////////////////////////////////// int FileMgrClass::Add_File (LPCTSTR filename, bool subdir_important) { // Assume failure int index = -1; // Param valid? ASSERT (filename != NULL); if ((filename != NULL) && (index == -1)) { // Ensure the path is complete CString path = Make_Full_Path (filename); LevelFileStruct *pentry = NULL; // Is this file already in the list? index = Find_File (path); if (index == -1) { // Allocate a new entry for our list pentry = new LevelFileStruct; ASSERT (pentry != NULL); // Set the file information pentry->m_Filename = path; pentry->m_RefCount = 0; // Add this entry to the list m_FileList.Add (pentry); index = Find_File (path); } else { pentry = m_FileList[index]; } // // Record whether or not we think the file's subdirectory // is important. // pentry->m_SubdirImportant |= subdir_important; // Increment the refcount on this entry pentry->m_RefCount ++; } // Return the index of the file return index; } ///////////////////////////////////////////////////////////////// // // Update_Texture_Cache // ///////////////////////////////////////////////////////////////// bool FileMgrClass::Update_Texture_Cache ( LPCTSTR start_path, RenderObjClass *prender_obj ) { // Assume failure bool retval = false; ASSERT (prender_obj != NULL); if (prender_obj != NULL) { // Assume success from here on out retval = true; // Generate a list of all the texture files required by this render object DynamicVectorClass texture_list; int count = Build_Texture_List (start_path, prender_obj, texture_list); // Loop through all the textures in our list and make sure the latest // version is in the cache directory for (int texture = 0; texture < count; texture ++) { // Should we now copy the texture file over? CString texture_file = texture_list[texture]; if (::GetFileAttributes (texture_file) != 0xFFFFFFFF) { // Is the texture file newer than the one we have in the cache? CString cache_path = m_TextureCachePath + CString ("\\") + ::Get_Filename_From_Path (texture_file); if (::Quick_Compare_Files (texture_file, cache_path) > 0) { // Everything is in order, so copy the texture file to the cache retval &= ::Copy_File (texture_file, cache_path, FALSE); } } } } // Return the true/false result code return retval; } ///////////////////////////////////////////////////////////////// // // Build_Texture_List // ///////////////////////////////////////////////////////////////// int FileMgrClass::Build_Texture_List ( LPCTSTR start_path, RenderObjClass *prender_obj, DynamicVectorClass &texture_list, bool brecurse ) { // Param valid? ASSERT (prender_obj != NULL); if (prender_obj) { CString path = start_path; ::Delimit_Path (path); // Get a list of texture files from the render object DynamicVectorClass dependency_list; prender_obj->Build_Texture_List (dependency_list); // Loop through all the texture files and try to assign paths to each one. for (int index = 0; index < dependency_list.Count (); index ++) { // Build a full path to the current texture file const char *filename = dependency_list[index]; CString full_path = path + CString (filename); full_path = ::Get_File_Mgr ()->Make_Full_Path (full_path); // Does the texture file exist in this location? if (Does_File_Exist (full_path) == false) { // Assume the texture file exists in the parent directory full_path = ::Up_One_Directory (::Strip_Filename_From_Path (full_path)); ::Delimit_Path (full_path); full_path += filename; } // Add this texture file to the list texture_list.Add (full_path); } dependency_list.Delete_All (); } // Return the count of textures in the list return texture_list.Count (); } ///////////////////////////////////////////////////////////////// // // Determine_File_Location // ///////////////////////////////////////////////////////////////// bool FileMgrClass::Determine_File_Location (LPCTSTR full_path, CString &real_location) { bool retval = false; // // Does the file exist in this location? // if (Does_File_Exist (full_path) == false) { CString filename = ::Get_Filename_From_Path (full_path); CString parent_dir = ::Up_One_Directory (::Strip_Filename_From_Path (full_path)); CString parent_path = ::Make_Path (parent_dir, filename); // // Does the file exist in the parent directory? // if (Does_File_Exist (parent_path) == false) { if (::Is_Texture_Filename (filename)) { // // Does this texture file exist in the global texture directory? // CString texture_path = ::Make_Path (GLOBAL_TEXTURE_PATH, filename); if (Does_File_Exist (texture_path)) { real_location = texture_path; retval = true; } } } else { real_location = parent_path; retval = true; } } else { real_location = full_path; retval = true; } return retval; } ///////////////////////////////////////////////////////////////// // // Build_File_List // ///////////////////////////////////////////////////////////////// void FileMgrClass::Build_File_List ( LPCTSTR start_path, RenderObjClass * render_obj, FILE_LIST & file_list ) { CString path = start_path; ::Delimit_Path (path); // Get a list of dependent files from the render object DynamicVectorClass dependency_list; render_obj->Build_Dependency_List (dependency_list); // Loop through all the files and try to assign paths to each one. for (int index = 0; index < dependency_list.Count (); index ++) { // Build a full path to the current file const char *filename = dependency_list[index]; CString full_path = ::Make_Path (path, filename); full_path = Make_Full_Path (full_path); // // Record that the subdir where this file lives is important // IF the subdir is returned by the render object. // bool subdir_important = (::strstr (filename, "+\\") != NULL); // // Attempt to find the file // CString real_location = full_path; Determine_File_Location (full_path, real_location); // // Add this file to the list // file_list.Add (FileInfoStruct (real_location, subdir_important)); } dependency_list.Delete_All (); return ; } ///////////////////////////////////////////////////////////////// // // Initialize_VSS // ///////////////////////////////////////////////////////////////// bool FileMgrClass::Initialize_VSS ( LPCTSTR ini_file_path, LPCTSTR username, LPCTSTR password ) { // Do we need to initialize the VSS database? if (m_bVSSInitialized == false) { // Attempt to open the database m_bVSSInitialized = m_DatabaseInterface->Open_Database (ini_file_path, username ? username : "User", password ? password : ""); m_bReadOnlyVSS = (m_DatabaseInterface->Is_Read_Only () == TRUE); // // Is this a special user? A special user is someone who doesn't // have full write access to the database. // if (::lstrcmpi (username, SPECIAL_USER_NAME) == 0) { m_IsSpecialUser = true; } } // Return the true/false result code return m_bVSSInitialized; } ///////////////////////////////////////////////////////////////// // // Is_File_In_VSS // ///////////////////////////////////////////////////////////////// bool FileMgrClass::Is_File_In_VSS (LPCTSTR filename) { // Assume failure bool retval = false; // State OK? if (m_bVSSInitialized) { retval = m_DatabaseInterface->Does_File_Exist (filename); } // Return the true/false result code return retval; } ///////////////////////////////////////////////////////////////// // // Build_Update_List // ///////////////////////////////////////////////////////////////// int FileMgrClass::Build_Update_List (DynamicVectorClass &update_list) { int count = 0; // State OK? ASSERT (m_bVSSInitialized); if (m_bVSSInitialized) { // Loop through all the files in our array for (int index = 0; index < m_FileList.Count (); index ++) { // Get a pointer to this entry LevelFileStruct *pentry = m_FileList[index]; // Ask VSS if we need to update this file. if (m_DatabaseInterface->Is_File_Different (pentry->m_Filename)) { update_list.Add (pentry); } } } // Return the count of items we added to the list return count; } ///////////////////////////////////////////////////////////////// // // Update_Files // ///////////////////////////////////////////////////////////////// bool FileMgrClass::Update_Files (DynamicVectorClass *pupdate_list) { // Asssume success bool retval = true; ASSERT (m_bVSSInitialized); // Do we need to build a list of files to generate ourselves? DynamicVectorClass *plist = pupdate_list; if (plist == NULL) { // Create a new list object plist = new DynamicVectorClass; ASSERT (plist != NULL); // Generate a list of files that need to be updated from VSS Build_Update_List (*plist); } // Loop through all the files in our array for (int index = 0; index < plist->Count (); index ++) { // Get a pointer to this entry LevelFileStruct *pentry = (*plist)[index]; // // Get the latest version from VSS if we don't already have the file // checked out. // if (m_DatabaseInterface->Get_File_Status (pentry->m_Filename) != AssetDatabaseClass::CHECKED_OUT_TO_ME) { retval &= m_DatabaseInterface->Get (pentry->m_Filename); } } // Free the temporary list if we need to if (plist != pupdate_list) { SAFE_DELETE (plist); } // Return the true/false result code return retval; } ///////////////////////////////////////////////////////////////// // // Update_File // ///////////////////////////////////////////////////////////////// bool FileMgrClass::Update_File (int index) { // Asssume failure bool retval = false; // Param valid? if ((index >= 0) && (index < m_FileList.Count ())) { // Update the file using its filename retval = Update_File (m_FileList[index]->m_Filename); } // Return the true/false result code return retval; } ///////////////////////////////////////////////////////////////// // // Update_File // ///////////////////////////////////////////////////////////////// bool FileMgrClass::Update_File (LPCTSTR filename) { // Asssume failure bool retval = false; // State valid? ASSERT (filename != NULL); ASSERT (m_bVSSInitialized); if ((filename != NULL) && m_bVSSInitialized) { // Assume success from here on out retval = true; // // Ensure the path is complete for the file // CString path = Make_Full_Path (filename); // // Get the latest version from VSS if we don't already have the file // checked out. // if ( ::GetFileAttributes (path) == 0xFFFFFFFF || m_DatabaseInterface->Get_File_Status (filename) != AssetDatabaseClass::CHECKED_OUT_TO_ME) { retval = m_DatabaseInterface->Get (path); } } // Return the true/false result code return retval; } ///////////////////////////////////////////////////////////////// // // Update_All_Files // ///////////////////////////////////////////////////////////////// bool FileMgrClass::Update_All_Files (LPCTSTR dest_path, LPCTSTR search_mask) { bool retval = false; // State valid? ASSERT (dest_path != NULL); ASSERT (m_bVSSInitialized); if ((dest_path != NULL) && m_bVSSInitialized) { // // Assume success from here on out // retval = m_DatabaseInterface->Get_All (dest_path, search_mask); } return retval; } ///////////////////////////////////////////////////////////////// // // Get_Subproject // ///////////////////////////////////////////////////////////////// bool FileMgrClass::Get_Subproject (LPCTSTR path) { // Asssume failure bool retval = false; // State valid? ASSERT (path != NULL); ASSERT (m_bVSSInitialized); if ((path != NULL) && m_bVSSInitialized) { // Ensure the path is complete for the file CString full_path = Make_Full_Path (path); // Get the files from VSS retval = m_DatabaseInterface->Get (full_path); } // Return the true/false result code return retval; } ///////////////////////////////////////////////////////////////// // // Set_Base_Path // ///////////////////////////////////////////////////////////////// void FileMgrClass::Set_Base_Path (LPCTSTR base) { // Store this base both in memory and in the registry m_BasePath = base; theApp.WriteProfileString (CONFIG_KEY, ASSET_DIR_VALUE, m_BasePath); // Ensure the directory is created if (Does_File_Exist (m_BasePath) == false) { ::CreateDirectory (base, NULL); } // Ensure the new base has a directory delimiter on the end if (m_BasePath[::lstrlen (m_BasePath) - 1] != '\\') { m_BasePath += "\\"; } // The new cache directory is simply a subdirectory of the base m_TextureCachePath = m_BasePath + "EditorCache"; if (::GetFileAttributes (m_TextureCachePath) == 0xFFFFFFFF) { ::CreateDirectory (m_TextureCachePath, NULL); } // // Add the texture cache to the search path // EditorFileFactoryClass::Add_Search_Path (m_TextureCachePath); return ; } ///////////////////////////////////////////////////////////////// // // Find_Files // ///////////////////////////////////////////////////////////////// void FileMgrClass::Find_Files ( LPCTSTR start_path, LPCTSTR wildcard, DynamicVectorClass & file_list, bool recurse ) { CString path = start_path; if (path[::lstrlen(path)-1] != '\\') { path += "\\"; } // Build a file spec from the starting path and the wildcard CString file_spec = path + wildcard; // Find all files that match this wildcard WIN32_FIND_DATA find_info = { 0 }; BOOL bcontinue = TRUE; for (HANDLE hfile_find = ::FindFirstFile (file_spec, &find_info); (hfile_find != INVALID_HANDLE_VALUE) && bcontinue; bcontinue = ::FindNextFile (hfile_find, &find_info)) { // Is this a file? if (!(find_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { // Add this file to our list CString filename = path + find_info.cFileName; file_list.Add (filename); } } // Close the search handle ::FindClose (hfile_find); hfile_find = INVALID_HANDLE_VALUE; if (recurse) { // Process all the subdirs file_spec = path + "*.*"; bcontinue = TRUE; for (hfile_find = ::FindFirstFile (file_spec, &find_info); (hfile_find != INVALID_HANDLE_VALUE) && bcontinue; bcontinue = ::FindNextFile (hfile_find, &find_info)) { // If this is a subdir, then recursively build the file list if ((find_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (find_info.cFileName[0] != '.')){ CString sub_dir = path + find_info.cFileName; Find_Files (sub_dir, wildcard, file_list, recurse); } } // Close the search handle ::FindClose (hfile_find); hfile_find = INVALID_HANDLE_VALUE; } return ; } ///////////////////////////////////////////////////////////////// // // Update_Model // ///////////////////////////////////////////////////////////////// bool FileMgrClass::Update_Model ( LPCTSTR local_path, LPCTSTR new_filename ) { // Assume failure bool retval = false; CWaitCursor wait_cursor; // // Display a dialog so the user doesn't close down the app // HWND hmain_wnd = ::AfxGetMainWnd ()->m_hWnd; HWND hupdate_dlg = ::Show_VSS_Update_Dialog (hmain_wnd); CString new_path = ::Strip_Filename_From_Path (new_filename); CString local_path_temp = local_path; ::Delimit_Path (local_path_temp); ::Delimit_Path (new_path); bool path_different = bool(::lstrcmpi (new_path, local_path_temp) != 0); // // Build a unique list of dependencies on this W3D file // UniqueListClass file_list; Build_Dependency_List (new_filename, file_list); // // Loop through all the files in our list // for (int index = 0; index < file_list.Count (); index ++) { // Get the full path, and its 2 components, of the current file. CString &full_path = file_list[index]; CString path = ::Strip_Filename_From_Path (full_path); CString filename = ::Get_Filename_From_Path (full_path); // The local version (in our asset tree) of this file should exist here. CString local_file = local_path_temp + filename; // // Check to see if we need to maintain this file's subdirectory... // bool subdir_important = (::strstr (full_path, "+\\") != NULL); if (subdir_important) { // // Ensure the subdirectory exists // CString sub_dir = local_path_temp + ::Get_Subdir_From_Full_Path (full_path); ::Create_Dir_If_Necessary (sub_dir); // // Build a path where the destination file lives in the sub-dir // local_file = sub_dir + CString ("\\") + filename; } // // Attempt to check out the latest version of this file // bool need_checkin = m_DatabaseInterface->Check_Out (local_file, false); // // If this file is newer than its local counterpart, copy it! // //if (path_different && ::Quick_Compare_Files (full_path, local_file) > 0) { if (path_different) { ::Copy_File (full_path, local_file, true); } // // Should we add this file to VSS, or update the existing? // if (need_checkin == false) { m_DatabaseInterface->Add_File (local_file); } else { m_DatabaseInterface->Check_In (local_file); } } // Remove the updating dialog ::Kill_VSS_Update_Dialog (hupdate_dlg); return retval; } ///////////////////////////////////////////////////////////////// // // Build_Dependency_List // ///////////////////////////////////////////////////////////////// void FileMgrClass::Build_Dependency_List ( LPCTSTR asset_filename, UniqueListClass & list ) { CString full_path = Make_Full_Path (asset_filename); CString path = ::Strip_Filename_From_Path (full_path); CString filename = ::Get_Filename_From_Path (asset_filename); CString asset_name = ::Asset_Name_From_Filename (filename); // Create an instance of the model so we can enumerate all the other // files this model is dependant on _pThe3DAssetManager->Set_Current_Directory (path); RenderObjClass *render_obj = _pThe3DAssetManager->Create_Render_Obj (asset_name); if (render_obj != NULL) { // Build a list of all the files used by this render object FILE_LIST file_list; Build_File_List (path, render_obj, file_list); // Make a unique list out of the file list for (int index = 0; index < file_list.Count (); index ++) { FileInfoStruct &info = file_list[index]; list.Add_Unique (info.m_Filename); } // Free the temporary render object MEMBER_RELEASE (render_obj); } else { // // This wasn't a render object file (could of been an animation), so // just add the file to the list (no other dependencies). // list.Add (full_path); } return ; } ///////////////////////////////////////////////////////////////// // // Update_Asset_Tree // ///////////////////////////////////////////////////////////////// bool FileMgrClass::Update_Asset_Tree (void) { return m_DatabaseInterface->Get_Subproject (m_BasePath); } ///////////////////////////////////////////////////////////////// // // Build_Global_Include_List // void FileMgrClass::Build_Global_Include_List (void) { // Ensure we have the latest copy from VSS Update_File (ALWAYS_INI_PATH); // Build the global include list Build_Include_List (ALWAYS_INI_PATH, m_GlobalIncludeFiles); return ; } ///////////////////////////////////////////////////////////////// // // Build_Include_List // ///////////////////////////////////////////////////////////////// void FileMgrClass::Build_Include_List ( LPCTSTR ini_filename, DynamicVectorClass &list ) { // Start with a fresh list of files list.Delete_All (); // Get a pointer to the INI file from the asset manager CString ini_path = Make_Full_Path (ini_filename); EditorINIClass *pini = _pThe3DAssetManager->Get_INI (ini_path); // Were we successful in getting a pointer to the INI file? ASSERT (pini != NULL); if (pini != NULL) { // Loop through all the assets in the ini file int instance_count = pini->Entry_Count ("Assets"); for (int index = 0; index < instance_count; index ++) { // Get the current file spec from the INI TCHAR filespec[MAX_PATH]; pini->Get_String ("Assets", pini->Get_Entry ("Assets", index), "", filespec, sizeof (filespec)); // Add the filespec to our list list.Add (filespec); } // Free the INI object SAFE_DELETE (pini); } return ; } ///////////////////////////////////////////////////////////////// // // Update_Global_Include_File_List // ///////////////////////////////////////////////////////////////// bool FileMgrClass::Update_Global_Include_File_List (void) { bool retval = false; // Attempt to checkout the INI file CString ini_path = Make_Full_Path (ALWAYS_INI_PATH); if (m_DatabaseInterface->Retry_Check_Out (ini_path, 10, 1000)) { // Create the INI file from our in-memory list EditorINIClass ini_file; for (int index = 0; index < m_GlobalIncludeFiles.Count (); index ++) { CString index_string; index_string.Format ("%d", index + 1); ini_file.Put_String ("Assets", index_string, (LPCTSTR)m_GlobalIncludeFiles[index]); } // Save the INI file FileClass * pini_file = _TheFileFactory->Get_File (ini_path); if (pini_file) { ini_file.Save (*pini_file); _TheFileFactory->Return_File (pini_file); } // Now check the INI file back in retval = m_DatabaseInterface->Retry_Check_In (ini_path, 10, 1000); } // Reutrn the true/false result code return retval; } ///////////////////////////////////////////////////////////////// // // Update // ///////////////////////////////////////////////////////////////// void FileMgrClass::Update (NodeClass *node, bool add_node) { // // Update the files this preset is dependent on // PresetClass *preset = node->Get_Preset (); if (preset != NULL) { Update (preset, add_node); } // // If this is a spawner, then update the files // its spawned object is dependent on as well. // if (node->Get_Type () == NODE_TYPE_SPAWNER) { SpawnerDefClass *definition = static_cast (preset->Get_Definition ()); if (definition != NULL) { // // Loop over all the possible spawned objects and make sure to load their assets // const DynamicVectorClass &list = definition->Get_Spawn_Definition_ID_List (); for (int index = 0; index < list.Count (); index ++) { PresetClass *preset = PresetMgrClass::Find_Preset (list[index]); if (preset != NULL) { Update (preset, add_node); } } } } return ; } ///////////////////////////////////////////////////////////////// // // Update // ///////////////////////////////////////////////////////////////// void FileMgrClass::Update (PresetClass *preset, bool add_node) { // // Get the list of dependencies from the preset // STRING_LIST file_list; preset->Get_All_Dependencies (file_list); // // Loop through all the files this preset is dependent on // for (int index = 0; index < file_list.Count (); index ++) { CString filename = file_list[index]; if (Is_Empty_Path (filename) == false) { if (add_node) { Add_Asset (filename); } else { Remove_Asset (filename); } } } return ; } ///////////////////////////////////////////////////////////////// // // Add_Asset // ///////////////////////////////////////////////////////////////// void FileMgrClass::Add_Asset (LPCTSTR filename) { RenderObjClass *render_obj = NULL; // // If this is a render object, then build a list of // dependencies // if (::Is_W3D_Filename (filename)) { CString asset_name = ::Asset_Name_From_Filename (filename); render_obj = ::Create_Render_Obj (asset_name); } if (render_obj != NULL) { // // Build a list of all the files used by this render object // CString full_path = Make_Full_Path (filename); CString start_path = ::Strip_Filename_From_Path (full_path); FILE_LIST file_list; Build_File_List (start_path, render_obj, file_list); // Loop through all the files in the list and add them to our internal // list (or update its ref count if its already there) for (int index = 0; index < file_list.Count (); index ++) { FileInfoStruct &info = file_list[index]; Add_File (Make_Full_Path (info.m_Filename), info.m_SubdirImportant); } MEMBER_RELEASE (render_obj); } else { Add_File (Make_Full_Path (filename), false); } return ; } ///////////////////////////////////////////////////////////////// // // Remove_Asset // ///////////////////////////////////////////////////////////////// void FileMgrClass::Remove_Asset (LPCTSTR filename) { RenderObjClass *render_obj = NULL; // // If this is a render object, then build a list of // dependencies // if (::Is_W3D_Filename (filename)) { CString asset_name = ::Asset_Name_From_Filename (filename); render_obj = ::Create_Render_Obj (asset_name); } if (render_obj != NULL) { // Build a list of all the files used by this render object CString full_path = Make_Full_Path (filename); CString start_path = ::Strip_Filename_From_Path (full_path); FILE_LIST file_list; Build_File_List (start_path, render_obj, file_list); // Loop through all the files in the list and add them to our internal // list (or update its ref count if its already there) for (int index = 0; index < file_list.Count (); index ++) { FileInfoStruct &info = file_list[index]; Remove_File (Find_File (Make_Full_Path (info.m_Filename))); } MEMBER_RELEASE (render_obj); } else { Remove_File (Find_File (Make_Full_Path (filename))); } return ; } ///////////////////////////////////////////////////////////////// // // Get_Preset_Library_Path // ///////////////////////////////////////////////////////////////// void FileMgrClass::Get_Preset_Library_Path (uint32 class_id, bool is_temp, CString &path) { CString directory = Make_Full_Path (PRESETS_PATH); // // Build a filename for the presets library // CString filename; if (is_temp == false) { filename.Format ("%d.ddb", class_id); } else { filename = TEMP_DB_FILENAME; } // // Build a fully qualified path from the directory and filename // path = ::Make_Path (directory, filename); return ; }