1573 lines
39 KiB
C++
1573 lines
39 KiB
C++
/*
|
|
** 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/***********************************************************************************************
|
|
*** 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 = "<Artist Tests>";
|
|
const char *PROXY_TESTS_FOLDER = "<Proxy Tests>";
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// 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<CString> 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<CString> 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<CString> &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<StringClass> 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<StringClass> 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<LevelFileStruct *> &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<LevelFileStruct *> *pupdate_list)
|
|
{
|
|
// Asssume success
|
|
bool retval = true;
|
|
|
|
ASSERT (m_bVSSInitialized);
|
|
|
|
// Do we need to build a list of files to generate ourselves?
|
|
DynamicVectorClass<LevelFileStruct *> *plist = pupdate_list;
|
|
if (plist == NULL) {
|
|
|
|
// Create a new list object
|
|
plist = new DynamicVectorClass<LevelFileStruct *>;
|
|
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<CString> & 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<CString> 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<CString> & 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<CString> &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<SpawnerDefClass *> (preset->Get_Definition ());
|
|
if (definition != NULL) {
|
|
|
|
//
|
|
// Loop over all the possible spawned objects and make sure to load their assets
|
|
//
|
|
const DynamicVectorClass<int> &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 ;
|
|
}
|
|
|