//===========================================================================// // File: Tool.cpp // //---------------------------------------------------------------------------// // Date Who Modification // // -------- --- ---------------------------------------------------------- // // 08/25/97 JMA Infrastructure changes // // 08/25/97 ECH Infrastructure changes // //---------------------------------------------------------------------------// // Copyright (C) 1994-97, Virtual World Entertainment, Inc. // // All Rights reserved worldwide // // This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL // //===========================================================================// #include "AdeptHeaders.hpp" #include "Tool.hpp" #include "RendererManager.hpp" #include "Application.hpp" #include "AudioRenderer.hpp" #include #include "ResourceImagePool.hpp" #include "ResourceEffectLibrary.hpp" #include "AudioSample.hpp" #include #define __mbsrchr(s,c) (char*)_mbsrchr((const unsigned char*)(s),(c)) Tool *Tool::Instance = NULL; //############################################################################# //######################## Tool ######################################### //############################################################################# //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Tool::Tool() { // //-------------------------------- // hook up the global tool pointer //-------------------------------- // Verify(Tool::Instance == NULL); Tool::Instance = this; Environment.HookGetFile = GetFileForGOS; Environment.HookDoesFileExist = FindFileForGOS; // //----------------------------------------- // Set up the path stack within the content //----------------------------------------- // stackSize = 128; filePathStack = new char*[stackSize]; Check_Pointer(filePathStack); stackIndex = 1; filePathStack[0] = ""; filePathStack[1] = "Content\\"; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Tool::~Tool() { Verify(stackIndex == 1); Check_Pointer(filePathStack); delete[] filePathStack; Verify(Tool::Instance == this); Tool::Instance = NULL; Environment.HookDoesFileExist = NULL; Environment.HookGetFile = NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Tool::TestInstance() { Verify(stackIndex >= 0 && stackIndex < stackSize); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Tool::PushFilePath(Stuff::NotationFile *file) { Check_Object(this); Check_Object(file); char *dir = strdup(file->GetFileName()); Check_Pointer(dir); char *p = __mbsrchr(dir, '\\'); if (p) *++p = '\0'; else *dir = '\0'; // //--------------------------------- // Add the directory onto the stack //--------------------------------- // Check_Pointer(filePathStack); if (++stackIndex == stackSize) { STOP(("Out of stack not handled")); } filePathStack[stackIndex] = dir; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Tool::PushFilePath(Stuff::FileStream *file) { Check_Object(this); Check_Object(file); char *dir = strdup(file->GetFileName()); Check_Pointer(dir); char *p = __mbsrchr(dir, '\\'); if (p) *++p = '\0'; else *dir = '\0'; // //--------------------------------- // Add the directory onto the stack //--------------------------------- // Check_Pointer(filePathStack); if (++stackIndex == stackSize) { STOP(("Out of stack not handled")); } filePathStack[stackIndex] = dir; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Tool::PopFilePath() { Check_Object(this); Check_Pointer(filePathStack); Verify(stackIndex > 0); char *dir = filePathStack[stackIndex--]; Check_Pointer(dir); free(dir); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void __stdcall Tool::GetFileForGOS( const char* file_name, BYTE** memory, DWORD* size ) { Check_Pointer(file_name); Tool *tool = Tool::Instance; Check_Object(tool); #ifdef LAB_ONLY strcpy(MWGameInfo::g_LastFileOpenRequest, "Tool::GetFileForGOS: "); strcpy(MWGameInfo::g_LastFileOpenRequest + 22, file_name); #endif // //----------------------------------------------------------------------- // If this is a rom file, find it in the resources and return the pointer //----------------------------------------------------------------------- // if (!strncmp(file_name, "ROM\\", 4)) { Resource texture(file_name+4); texture.LoadData(); *memory = static_cast(texture.GetPointer()); *size = texture.GetSize(); texture.AbandonData(); return; } // //-------------------------------------------------- // Only do the search if we don't start with content //-------------------------------------------------- // SPEW(("sagem", "file=%s", file_name)); if (_strnicmp(file_name, "content\\", 8)) { Check_Pointer(tool->filePathStack); Verify((unsigned)tool->stackIndex < (unsigned)tool->stackSize); Check_Pointer(tool->filePathStack[tool->stackIndex]); Str_Copy( FileStream::RedirectedName, tool->filePathStack[tool->stackIndex], sizeof(FileStream::RedirectedName) ); Verify( *FileStream::RedirectedName == '\0' || FileStream::RedirectedName[strlen(FileStream::RedirectedName)-1] == '\\' ); #ifdef LAB_ONLY strcat(MWGameInfo::g_LastFileOpenRequest, " --Redirected-> "); strcat(MWGameInfo::g_LastFileOpenRequest + 15, FileStream::RedirectedName); #endif // //----------------------------------------------------- // for each directory in the path, try to find the file //----------------------------------------------------- // while (true) { // //------------------------------------------------------------------- // Find the separator character, and append the file name to the path //------------------------------------------------------------------- // char *p = __mbsrchr((char*)FileStream::RedirectedName, '\\'); if (p) Str_Copy( p+1, file_name, sizeof(FileStream::RedirectedName) - (p - FileStream::RedirectedName) - 1 ); else Str_Copy( FileStream::RedirectedName, file_name, sizeof(FileStream::RedirectedName) ); // //----------------------------------------- // If the file exists, go ahead and open it //----------------------------------------- // if (gos_DoesFileExist(FileStream::RedirectedName)) { FileStream::IsRedirected=true; gos_PushCurrentHeap(FileStream::s_Heap); gos_GetFile(FileStream::RedirectedName, memory, size); gos_PopCurrentHeap(); return; } // //------------------------------------------------------------------- // Since it doesn't exist, we need to clip off the last directory and // try again. If there was no separator, no file will be found //------------------------------------------------------------------- // if (p) *p = '\0'; else break; } } FileStream::IsRedirected = false; gos_PushCurrentHeap(FileStream::s_Heap); gos_GetFile(file_name, memory, size); gos_PopCurrentHeap(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // bool __stdcall Tool::FindFileForGOS(const char* file_name) { Check_Pointer(file_name); Tool *tool = Tool::Instance; Check_Object(tool); // //-------------------------------------------------- // Only do the search if we don't start with content //-------------------------------------------------- // if (_strnicmp(file_name, "content\\", 8)) { Check_Pointer(tool->filePathStack); Verify((unsigned)tool->stackIndex < (unsigned)tool->stackSize); Check_Pointer(tool->filePathStack[tool->stackIndex]); Str_Copy( FileStream::RedirectedName, tool->filePathStack[tool->stackIndex], sizeof(FileStream::RedirectedName) ); // //----------------------------------------------------- // for each directory in the path, try to find the file //----------------------------------------------------- // while (true) { // //------------------------------------------------------------------- // Find the separator character, and append the file name to the path //------------------------------------------------------------------- // char *p = __mbsrchr((char*)FileStream::RedirectedName, '\\'); if (p) Str_Copy( p+1, file_name, sizeof(FileStream::RedirectedName) - (p - FileStream::RedirectedName) - 1 ); else Str_Copy( FileStream::RedirectedName, file_name, sizeof(FileStream::RedirectedName) ); // //----------------------------------------- // If the file exists, go ahead and open it //----------------------------------------- // if (gos_DoesFileExist(FileStream::RedirectedName)) { FileStream::IsRedirected = true; return true; } // //------------------------------------------------------------------- // Since it doesn't exist, we need to clip off the last directory and // try again. If there was no separator, no file will be found //------------------------------------------------------------------- // if (p) *p = '\0'; else break; } } FileStream::IsRedirected = false; return gos_DoesFileExist(file_name); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // const char* Tool::GetToolFileName(const char* file_name) { Check_Pointer(file_name); const char* result = strstr(file_name, "Content\\"); if (!result) { result = strstr(file_name, "content\\"); if (!result) return file_name; } Check_Pointer(result); return result+8; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Entity::ClassData* Tool::ConstructGameModel( MemoryStream *model_stream, const char *model_class, NotationFile *model_file ) { Check_Object(this); Check_Object(model_stream); Check_Pointer(model_class); Check_Object(model_file); #if defined(_ARMOR) int stack_index = stackIndex; #endif // //----------------------------------- // Find the class data for this model //----------------------------------- // RegisteredClass::ClassData *class_data; Entity::ClassData *entity_class_data; class_data = Entity::FindClassData(model_class); Check_Object(class_data); entity_class_data = Cast_Pointer(Entity::ClassData*, class_data); Check_Object(entity_class_data); // //-------------------------------------------------------------- // Create the game model parameters and call the creation method //-------------------------------------------------------------- // Entity::GameModel::Script script( model_stream, model_file, entity_class_data ); Entity::GameModel::Factory game_model_factory = entity_class_data->modelFactory; Check_Pointer(game_model_factory); (*game_model_factory)(&script); Verify(stack_index == stackIndex); return entity_class_data; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ResourceID Tool::MakeNewGameModel( const char *model_name, const char *model_class ) { Check_Object(this); Check_Pointer(model_name); Check_Pointer(model_class); // //--------------------------------------------------------------------- // Create the New Model Resource. If it is already there return the ID //--------------------------------------------------------------------- // MString game_model_name = model_name; game_model_name += "{GameModel}"; Resource model_resource(game_model_name); if (model_resource.DoesResourceExist() && model_resource.IsResourceUpToDate()) { Check_Object(&model_resource); // //---------------------------------------------------------------- // In order to deal with partial builds we have to give our parent // our file dependencies //---------------------------------------------------------------- // if (Resource::ParentFileDependencies) model_resource.AddFileDependenciesTo(Resource::ParentFileDependencies); return model_resource.GetResourceID(); } // //----------------------------------- // Find the class data for this model //----------------------------------- // RegisteredClass::ClassData *class_data; Entity::ClassData *entity_class_data; class_data = Entity::FindClassData(model_class); Check_Object(class_data); entity_class_data = Cast_Pointer(Entity::ClassData*, class_data); Check_Object(entity_class_data); // //-------------------------------------------------------------- // Create the game model parameters and call the creation method //-------------------------------------------------------------- // DynamicMemoryStream model_stream; Entity::GameModel::Script script( &model_stream, NULL, entity_class_data ); Entity::GameModel::Factory game_model_factory = entity_class_data->modelFactory; Check_Pointer(game_model_factory); (*game_model_factory)(&script); // //---------------------------------- //Save the GameModel Resource Stream //---------------------------------- // Check_Object(entity_class_data); model_resource.Save(&model_stream, NULL); STOP(("Not updated")); Check_Object(&model_resource); return model_resource.GetResourceID(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Entity::ClassData* Tool::ConstructDataList( Resource *resource, const char* model_name ) { Check_Object(this); Check_Object(resource); Check_Pointer(model_name); #if defined(_ARMOR) int stack_index = stackIndex; #endif // //--------------------------------------------------------------------------------------- // First open this up as a filestream to get a clue on the name - no need to expand it if // it already exists //--------------------------------------------------------------------------------------- // if (!gos_DoesFileExist(model_name)) STOP(("%s can't be found!")); // //--------------------------------------------------- // See if the data file can be found in the resources //--------------------------------------------------- // if (FileStream::IsRedirected) { model_name = FileStream::RedirectedName; FileStream::IsRedirected = false; } Check_Pointer(model_name); MString model_file_name = model_name; resource->FindName(model_file_name); if (resource->DoesResourceExist() && resource->IsResourceUpToDate()) { Check_Object(resource); // //---------------------------------------------------------------- // In order to deal with partial builds we have to give our parent // our file dependencies //---------------------------------------------------------------- // if (Resource::ParentFileDependencies && !resource->IsRegistered()) resource->AddFileDependenciesTo(Resource::ParentFileDependencies); // //----------------------------------------------- // Figure out the class data object and return it //----------------------------------------------- // RegisteredClass::ClassID class_id = Entity::GetClassIDFromDataListID(resource->GetResourceID()); Entity::ClassData *class_data = Cast_Pointer( Entity::ClassData*, RegisteredClass::FindClassData(class_id) ); Check_Object(class_data); Verify(stack_index == stackIndex); return class_data; } // //-------------------------------------------------------------------- // We are building this model, so set the file path to the model file, // then setup our initial dependencies to match the model file //-------------------------------------------------------------------- // NotationFile model_file(model_file_name); PushFilePath(&model_file); FileDependencies *parent_dependencies = Resource::ParentFileDependencies; FileDependencies data_dependencies(*model_file.GetFileDependencies()); // //-------------------- // Find the class name //-------------------- // const char *model_class; Page *page = model_file.GetPage("GameData"); Check_Object(page); page->GetEntry("Class", &model_class, true); // //-------------------------------------------- // Create the memory stream for the game model //-------------------------------------------- // FileDependencies model_dependencies(*model_file.GetFileDependencies()); Resource::ParentFileDependencies = &model_dependencies; MString game_model_name = model_file_name; game_model_name += "{GameModel}"; Resource model_resource(game_model_name); DynamicMemoryStream model_stream; Entity::ClassData *entity_class_data = ConstructGameModel( &model_stream, model_class, &model_file ); Check_Object(entity_class_data); model_resource.Save(&model_stream, &model_dependencies); Check_Object(&model_resource); if (!model_resource.IsRegistered()) data_dependencies.AddDependencies(&model_dependencies); // //------------------------------------------------------ // Create a memory stream to hold data list resource IDs //------------------------------------------------------ // Check_Object(RendererManager::Instance); int model_list_size = RendererManager::Instance->GetModelListSize(); Verify(model_list_size >= 1); DynamicArrayOf resource_ids(ResourceID::Null, model_list_size); resource_ids[RendererManager::ReservedForGameModelRendererType] = model_resource.GetResourceID(); int i; for(i=(RendererManager::ReservedForGameModelRendererType + 1); iMakeNoteIterator(); Check_Object(renderers); Note *renderer; while ((renderer = renderers->ReadAndNext()) != NULL) { Check_Object(renderer); const char *renderer_name = renderer->GetName(); Check_Pointer(renderer_name); Check_Object(RendererManager::Instance); int renderer_type = RendererManager::Instance->FindRendererType(renderer_name); Verify(renderer_type > RendererManager::ReservedForGameModelRendererType); Verify(renderer_type < model_list_size); resource_ids[renderer_type] = ResourceID(resource->GetResourceID().m_fileID, 0); NotationFile renderer_file; renderer->GetEntry(&renderer_file); FileDependencies renderer_dependencies(*renderer_file.GetFileDependencies()); Resource::ParentFileDependencies = &renderer_dependencies; CreateRendererData( &resource_ids[renderer_type], entity_class_data, &renderer_file, renderer_type ); data_dependencies.AddDependencies(&renderer_dependencies); } Check_Object(renderers); delete renderers; } // //----------------------- // Save out the data list //----------------------- // MemoryStream res_id_stream(resource_ids.GetData(), resource_ids.GetSize()); resource->Save(&res_id_stream, &data_dependencies); Resource::ParentFileDependencies = parent_dependencies; if (parent_dependencies && !resource->IsRegistered()) parent_dependencies->AddDependencies(&data_dependencies); // //--------- // Clean up //--------- // PopFilePath(); Verify(stack_index == stackIndex); return entity_class_data; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Entity::CreateMessage* Tool::ConstructCreateMessage( Stuff::MemoryStream *message_stream, Page *page, ReplicatorID *base_id ) { Check_Object(this); Check_Object(message_stream); Check_Object(page); Check_Object(base_id); #if defined(_ARMOR) int stack_index = stackIndex; #endif // //---------------------------------------------------------------------- // Remember where the id started so we can compute the span of id's used // in this message //---------------------------------------------------------------------- // ReplicatorID original_id = *base_id; // //--------------------------------------------------------------------- // Locate the model file entry and make sure it is already in resources //--------------------------------------------------------------------- // const char* model_name; page->GetEntry("Model", &model_name, true); Entity::CreateMessage::Script script; script.classData = ConstructDataList(&script.modelResource, model_name); Check_Object(script.classData); // //-------------------------------------------------------------- // Now that we have the data object for the model type, call the // appropriate make message factory //-------------------------------------------------------------- // script.messageStream = message_stream; script.instancePage = page; script.baseID = base_id; Entity::CreateMessage::Factory factory = (Entity::CreateMessage::Factory)script.classData->messageFactory; Check_Pointer(factory); (*factory)(&script); // //------------------------------------------------------------------- // Get the message, and set the span on the replicant ID to match the // number of ids used by this and its children //------------------------------------------------------------------- // Entity::CreateMessage *message = Cast_Pointer( Entity::CreateMessage*, message_stream->GetPointer() ); Check_Object(message); message->replicatorID.localID = static_cast(script.baseID->localID - original_id.localID); Verify(stack_index == stackIndex); return message; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Tool::ConstructCreateMessage( Resource *resource, NotationFile *instance_file, ReplicatorID *base_id ) { Check_Object(this); Check_Object(resource); Check_Object(instance_file); Check_Object(base_id); #if defined(_ARMOR) int stack_index = stackIndex; #endif // //--------------------------------------------------------- // Open up the instance file and push the path on the stack //--------------------------------------------------------- // const char* instance_file_name = instance_file->GetFileName(); PushFilePath(instance_file); // //---------------------------------------- // See if the resource needs to be rebuilt //---------------------------------------- // resource->FindName(instance_file_name); if (resource->DoesResourceExist() && resource->IsResourceUpToDate()) { // //-------------------------------------------------------------------- // We need to bump the replicator ID, so cast the resource as a create // message and apply the bump number to the base id //-------------------------------------------------------------------- // resource->LoadData(); Entity::CreateMessage *message = Cast_Pointer( Entity::CreateMessage*, resource->GetPointer() ); Check_Object(message); *base_id += message->replicatorID.localID; PopFilePath(); Verify(stack_index == stackIndex); if (Resource::ParentFileDependencies && !resource->IsRegistered()) resource->AddFileDependenciesTo(Resource::ParentFileDependencies); return; } // //----------------------------------------------------------------------- // For instances, assume the first page is our instance, so take whatever // name it has //----------------------------------------------------------------------- // FileDependencies instance_dep(*instance_file->GetFileDependencies()); FileDependencies *parent = Resource::ParentFileDependencies; Resource::ParentFileDependencies = &instance_dep; NotationFile::PageIterator *instance_pages = instance_file->MakePageIterator(); Check_Object(instance_pages); Page *instance = instance_pages->GetCurrent(); if (!instance) STOP(("Error: %s has no instance pages!", instance_file->GetFileName())); Check_Object(instance); // //------------------------------ // Put the message into a stream //------------------------------ // DynamicMemoryStream instance_stream; ConstructCreateMessage( &instance_stream, instance, base_id ); resource->Save(&instance_stream, &instance_dep); if (parent && !resource->IsRegistered()) parent->AddDependencies(&instance_dep); Resource::ParentFileDependencies = parent; // //------------- // Now clean up //------------- // PopFilePath(); Check_Object(instance_pages); delete instance_pages; Verify(stack_index == stackIndex); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Entity::CreateMessage* Tool::ConstructCreateMessage( Stuff::MemoryStream *message_stream, NotationFile *instance_file, ReplicatorID *base_id ) { Check_Object(this); Check_Object(message_stream); Check_Pointer(instance_file); Check_Object(base_id); #if defined(_ARMOR) int stack_index = stackIndex; #endif // //--------------------------------------------------------- // Open up the instance file and push the path on the stack //--------------------------------------------------------- // PushFilePath(instance_file); // //----------------------------------------------------------------------- // For instances, assume the first page is our instance, so take whatever // name it has //----------------------------------------------------------------------- // NotationFile::PageIterator *instance_pages = instance_file->MakePageIterator(); Check_Object(instance_pages); Page *instance = instance_pages->GetCurrent(); Check_Object(instance); // //------------------------------ // Put the message into a stream //------------------------------ // Entity::CreateMessage *message = ConstructCreateMessage( message_stream, instance, base_id ); // //------------- // Now clean up //------------- // PopFilePath(); Check_Object(instance_pages); delete instance_pages; Verify(stack_index == stackIndex); return message; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Tool::BuildResources( Stuff::NotationFile *build_file, DWORD content_version, Stuff::FileDependencies *dependencies, short level, __int64 parent_build_age ) { Check_Object(this); Check_Object(build_file); Verify(Application::BuildOK); #if defined(_ARMOR) int stack_index = stackIndex; #endif // //------------------------------------------------------------------- // Create the resource directories (if they don't exist) and bump the // file ID //------------------------------------------------------------------- // if (level++ == -1) { if (!gos_DoesFileExist("Resource")) gos_CreateDirectory("Resource"); FileStream::IsRedirected = false; if (!gos_DoesFileExist("Resource\\Maps")) gos_CreateDirectory("Resource\\Maps"); FileStream::IsRedirected = false; if (!gos_DoesFileExist("Resource\\Missions")) gos_CreateDirectory("Resource\\Missions"); FileStream::IsRedirected = false; if (!gos_DoesFileExist("Resource\\Variants")) gos_CreateDirectory("Resource\\Variants"); FileStream::IsRedirected = false; PushFilePath(build_file); } // //----------------------------------------- // Spin through all the entries in the file //----------------------------------------- // Page *null_page = build_file->FindPage(""); if (null_page) { Check_Object(null_page); Page::NoteIterator *file_entries = null_page->MakeNoteIterator(); Check_Object(file_entries); Note *file_entry; while ((file_entry = file_entries->ReadAndNext()) != NULL) { Check_Object(file_entry); // //------------------------------- // Open up the next file to parse //------------------------------- // const char* parse_filename = file_entry->GetName(); Check_Pointer(parse_filename); NotationFile parse_file(parse_filename, NotationFile::NonEmpty); parse_filename = parse_file.GetFileName(); // //------------------------------------------------------- // Figure out how old it is and push it on the path stack //------------------------------------------------------- // __int64 build_age = gos_FileTimeStamp(parse_filename); if (build_age < parent_build_age) build_age = parent_build_age; PushFilePath(&parse_file); // //------------------------------------------------------------ // Each page name will be the name of a resource file to build //------------------------------------------------------------ // NotationFile::PageIterator *resource_file_pages = parse_file.MakePageIterator(); Check_Object(resource_file_pages); Page *resource_file_entry = resource_file_pages->ReadAndNext(); Verify(!resource_file_pages->ReadAndNext()); Check_Object(resource_file_entry); const char* resource_file_name = resource_file_entry->GetName(); // //-------------------------------------------------------------------- // Delete the file if it is older than the build file, then open it up //-------------------------------------------------------------------- // __int64 res_file_age = 0; if (gos_DoesFileExist(resource_file_name)) res_file_age = gos_FileTimeStamp(resource_file_name); bool dirty = res_file_age < build_age; FileStream::IsRedirected = false; MString dep_filename = resource_file_name; char *p = strrchr(dep_filename, '.'); if (p) strcpy(p+1, "dep"); if (!gos_DoesFileExist(dep_filename)) dirty = true; FileStream::IsRedirected = false; ResourceFile *res_file = ResourceManager::Instance->OpenResourceFile( resource_file_name, dep_filename, level, content_version, true, dirty ); // //------------------------------------------------------- // If we have dependencies, write them into resource zero //------------------------------------------------------- // { Resource build_dependencies(resource_file_name); if (!build_dependencies.DoesResourceExist()) { unsigned length = dependencies->m_fileNameStream.GetBytesUsed(); if (length>0) { MemoryStream chain( static_cast(dependencies->m_fileNameStream.GetPointer()) - length, length, length ); build_dependencies.Save(&chain, dependencies); } else { MemoryStream chain("", 1, 1); build_dependencies.Save(&chain, NULL); } } Verify(build_dependencies.GetResourceID().GetRecordID() == ResourceID::BuildDependenciesRecordID); } // //----------------------------------------------------------------- // Remember the state of the effect library prior to our build file // so we can restore to it after our children are created //----------------------------------------------------------------- // Check_Object(gosFX::EffectLibrary::Instance); unsigned old_effect_count = gosFX::EffectLibrary::Instance->GetLength(); FileDependencies old_deps = gosFX::EffectLibrary::Instance->m_fileDependencies; // //------------------------------------- // Parse the build file and save it out //------------------------------------- // bool core = ParseBuildFile(res_file, resource_file_entry); Check_Object(resource_file_pages); delete resource_file_pages; res_file->Save(); res_file->UnloadRecordData(); // //----------------------------------------- // If this is core, ignore the dependencies //----------------------------------------- // if (core) { NotationFile children; file_entry->GetEntry(&children); BuildResources( &children, content_version, dependencies, level, build_age ); } // //-------------------------- // Otherwise, write them out //-------------------------- // else { Check_Object(dependencies); FileDependencies deps(*dependencies); deps.AddDependency(resource_file_name); NotationFile children; file_entry->GetEntry(&children); BuildResources( &children, content_version, &deps, level, build_age ); } delete res_file; Check_Object(gosFX::EffectLibrary::Instance); gosFX::EffectLibrary::Instance->SetLength(old_effect_count); gosFX::EffectLibrary::Instance->m_fileDependencies = old_deps; PopFilePath(); } Check_Object(file_entries); delete file_entries; } if (!level) { Check_Object(FileStreamManager::Instance); FileStreamManager::Instance->PurgeFileCompareCache(); PopFilePath(); } Verify(stack_index == stackIndex); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // bool Tool::ParseBuildFile( ResourceFile *res_file, Stuff::Page *resource_file_entry ) { Check_Object(this); Check_Object(res_file); #if defined(_ARMOR) int stack_index = stackIndex; #endif // //------------------------------------------------------- // Look for the effects entry. If one is there, build it //------------------------------------------------------- // ResourceID last_id(res_file->GetFileID(),-1); ResourceID res_id(res_file); ChainOf* effects = resource_file_entry->MakeNoteChain("effects"); if (!effects->IsEmpty()) { Resource resource("{effects}"); if (!resource.DoesResourceExist()) resource.Save(NULL, NULL); last_id = resource.GetResourceID(); } // //----------------------------------------------------------------- // Make a list of all the entries within the page, and spin through // them, constructing a single empty resource for each one //----------------------------------------------------------------- // Page::NoteIterator *file_entries = resource_file_entry->MakeNoteIterator(); Check_Object(file_entries); Note *file_entry; while ((file_entry = file_entries->ReadAndNext()) != NULL) { Check_Object(file_entry); // //--------------------------------------------------- // Look at the type of entry to see what we should do //--------------------------------------------------- // const char* entry_type = file_entry->GetName(); Check_Pointer(entry_type); const char* entry_filename = NULL; file_entry->GetEntry(&entry_filename); if (!entry_filename) STOP(( "%s: [%s]%s is a bad entry!", resource_file_entry->GetNotationFile()->GetFileName(), resource_file_entry->GetName(), entry_type )); Check_Pointer(entry_filename); // //---------------------------------------------------------------- // If we are an instance, go ahead and build the make message into // the resources //---------------------------------------------------------------- // if (IsRegisterable(entry_type)) { Resource data_resource(entry_filename); if (!data_resource.DoesResourceExist()) data_resource.Save(NULL, NULL); if (last_id.GetRecordID() < 65535) { if (data_resource.GetResourceID().GetFileID() != last_id.GetFileID()) { PAUSE(( "Error: Registered resource %s already appears in resource file %d", data_resource.GetName(), data_resource.GetResourceID().GetFileID() )); } else Verify(data_resource.GetResourceID().GetRecordID() == last_id.GetRecordID()+1); } last_id = data_resource.GetResourceID(); } } res_file->SetLastRegisteredResourceID(last_id); // //----------------------------------------------------------------------- // Store each individual effect library in the resource file, concatenate // them into the main library, and keep track of all effect libraries // created //----------------------------------------------------------------------- // Check_Object(gosFX::EffectLibrary::Instance); DynamicArrayOf effect_IDs(effects->GetSize()); unsigned i=0; Check_Object(gosFX::EffectLibrary::Instance); ChainIteratorOf effect_iterator(effects); while ((file_entry = effect_iterator.ReadAndNext()) != NULL) { Check_Object(file_entry); const char* effects_filename; file_entry->GetEntry(&effects_filename); // //--------------------------------------------------- // Open up the effect file and gets its real filename //--------------------------------------------------- // FileStream stream(effects_filename); effects_filename = stream.GetFileName(); Resource resource(effects_filename); // //-------------------------------------------------- // If the resource needs to be refreshed, refresh it //-------------------------------------------------- // if (!resource.DoesResourceExist() || !resource.IsResourceUpToDate()) { FileDependencies effects_dependencies; effects_dependencies.AddDependency(&stream); resource.Save(&stream, &effects_dependencies); } // //--------------------------------------------- // Load the effects library and remember its ID //--------------------------------------------- // Verify(resource.DoesResourceExist()); gosFX::EffectLibrary::Instance->m_fileDependencies.AddDependency(effects_filename); resource.LoadData(); gosFX::EffectLibrary::Instance->Load(&resource); effect_IDs[i++] = resource.GetResourceID(); } delete effects; // //----------------------------------------------------------------------- // If we actually had effect libraries, save the list out to the resource // file now //----------------------------------------------------------------------- // if (i>0) { Resource resource("{effects}"); if (!resource.DoesResourceExist()) { MemoryStream stream( &effect_IDs[0], effect_IDs.GetSize(), effect_IDs.GetSize() ); resource.Save(&stream, &gosFX::EffectLibrary::Instance->m_fileDependencies); } } // //--------------------------------------------------------------------- // Look for the texture pool entry. We build the textures here so that // the texture name lookups happen as quickly as possible //--------------------------------------------------------------------- // NotationFile audio_hint; if (resource_file_entry->GetEntry("soundpool", &audio_hint)) AudioSample::BuildSoundPool(&audio_hint); // //-------------------------------- // Build each resource in the file //-------------------------------- // file_entries->First(); while ((file_entry = file_entries->ReadAndNext()) != NULL) { Check_Object(file_entry); const char* entry_type = file_entry->GetName(); Check_Pointer(entry_type); const char* entry_filename = NULL; file_entry->GetEntry(&entry_filename); Check_Pointer(entry_filename); BuildResource(entry_type, entry_filename); } // //--------------------------------------------------------------------- // Look for the texture pool entry. We build the textures here so that // the texture name lookups happen as quickly as possible //--------------------------------------------------------------------- // NotationFile hint_file; if (resource_file_entry->GetEntry("texturepool", &hint_file)) ResourceImagePool::BuildTexturePool(&hint_file); // //--------- // Clean up //--------- // bool core=false; resource_file_entry->GetEntry("Core", &core); Check_Object(file_entries); delete file_entries; res_file->Save(); Verify(stack_index == stackIndex); return core; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // bool Tool::IsRegisterable(const char* entry_type) { Check_Object(this); Check_Pointer(entry_type); return !_stricmp(entry_type, "instance") || !_stricmp(entry_type, "data") || !_stricmp(entry_type, "file") || !_stricmp(entry_type, "notation"); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Tool::BuildResource( const char* entry_type, const char* entry_filename ) { Check_Object(this); Check_Pointer(entry_type); Check_Pointer(entry_filename); #if defined(_ARMOR) int stack_index = stackIndex; #endif // //---------------------------------------------------------------- // If we are an instance, go ahead and build the make message into // the resources //---------------------------------------------------------------- // if (!_stricmp(entry_type, "instance")) { NotationFile instance_file(entry_filename, NotationFile::NonEmpty); Resource instance_resource; ReplicatorID base_id = ReplicatorID::Null; ConstructCreateMessage( &instance_resource, &instance_file, &base_id ); } // //-------------------------------------- // If we are a data list, construct that //-------------------------------------- // else if (!_stricmp(entry_type, "data")) { Resource data_resource; ConstructDataList(&data_resource, entry_filename); } // //------------------------------------- // Put a notation file in the resources //------------------------------------- // else if (!_stricmp(entry_type, "notation")) { NotationFile notation_file(entry_filename, NotationFile::NonEmpty); const char* file_name = notation_file.GetFileName(); Check_Pointer(file_name); Resource resource(file_name); if (!resource.DoesResourceExist() || !resource.IsResourceUpToDate()) { DynamicMemoryStream stream; notation_file.Write(&stream); resource.Save(&stream, notation_file.GetFileDependencies()); } } // //------------------------------------- // Put a general file in the resources //------------------------------------- // else if (!_stricmp(entry_type, "file")) { FileStream file(entry_filename); const char* file_name = file.GetFileName(); Check_Pointer(file_name); Resource resource(file_name); if (!resource.DoesResourceExist() || !resource.IsResourceUpToDate()) { FileDependencies file_dep; file_dep.AddDependency(&file); resource.Save(&file, &file_dep); } } // //-------------------------------------------------------- // Put a whole directory of general files in the resources //-------------------------------------------------------- // else if (!_stricmp(entry_type, "directory")) { MString path = entry_filename; path += '\\'; Directory directory(path + "*.*"); const char *file_name; while ((file_name = directory.GetCurrentFileName()) != NULL) { FileStream file(path+file_name); file_name = file.GetFileName(); Check_Pointer(file_name); Resource resource(file_name); if (!resource.DoesResourceExist() || !resource.IsResourceUpToDate()) { FileDependencies file_dep; file_dep.AddDependency(&file); resource.Save(&file, &file_dep); } directory.AdvanceCurrentFile(); } } Verify(stack_index == stackIndex); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Tool::CreateRendererData( ResourceID *stream_resource, Entity::ClassData *class_data, NotationFile *renderer_file, int renderer_type ) { Check_Object(stream_resource); Check_Pointer(class_data); Check_Object(renderer_file); PushFilePath(renderer_file); switch (renderer_type) { case RendererManager::VideoRendererType: VideoRenderer::CreateRendererData( stream_resource, class_data, renderer_file ); break; case RendererManager::AudioRendererType: AudioRenderer::CreateRendererData( stream_resource, class_data, renderer_file ); break; default: STOP(("Unknown renderer type!")); } PopFilePath(); }