void CGameGraphBuilder::save_cross_table (const float &start, const float &amount) { Progress (start); Msg ("Saving cross table"); // CTimer timer; // timer.Start (); CMemoryWriter tMemoryStream; CGameLevelCrossTable::CHeader tCrossTableHeader; tCrossTableHeader.dwVersion = XRAI_CURRENT_VERSION; tCrossTableHeader.dwNodeCount = level_graph().header().vertex_count(); tCrossTableHeader.dwGraphPointCount = graph().header().vertex_count(); tCrossTableHeader.m_level_guid = level_graph().header().guid(); tCrossTableHeader.m_game_guid = m_graph_guid; tMemoryStream.open_chunk (CROSS_TABLE_CHUNK_VERSION); tMemoryStream.w (&tCrossTableHeader,sizeof(tCrossTableHeader)); tMemoryStream.close_chunk (); tMemoryStream.open_chunk (CROSS_TABLE_CHUNK_DATA); for (int i=0, n=level_graph().header().vertex_count(); i<n; i++) { CGameLevelCrossTable::CCell tCrossTableCell; tCrossTableCell.tGraphIndex = (GameGraph::_GRAPH_ID)m_results[i]; VERIFY (graph().header().vertex_count() > tCrossTableCell.tGraphIndex); tCrossTableCell.fDistance = float(m_distances[tCrossTableCell.tGraphIndex][i])*level_graph().header().cell_size(); tMemoryStream.w (&tCrossTableCell,sizeof(tCrossTableCell)); } tMemoryStream.close_chunk(); // Msg ("CT:SAVE : %f",timer.GetElapsed_sec()); // Msg ("Flushing cross table"); #ifdef PRIQUEL tMemoryStream.save_to (m_cross_table_name); #else // PRIQUEL string_path file_name; strconcat (sizeof(file_name), file_name,*m_level_name,CROSS_TABLE_NAME_RAW); tMemoryStream.save_to (file_name); #endif // PRIQUEL // Msg ("CT:SAVE : %f",timer.GetElapsed_sec()); // Msg ("Freiing cross table resources"); m_marks.clear (); m_mark_stack.clear (); m_distances.clear (); m_current_fringe.clear (); m_next_fringe.clear (); // Msg ("CT:SAVE : %f",timer.GetElapsed_sec()); Progress (start + amount); }
void vfSaveVertices(CMemoryWriter &tMemoryStream, u32 &dwOffset, u32 &dwPointOffset, LEVEL_POINT_STORAGE *tpLevelPoints) { GRAPH_VERTEX_IT I = m_tpVertices.begin(); GRAPH_VERTEX_IT E = m_tpVertices.end(); GameGraph::CVertex tVertex; for ( ; I != E; I++) { tVertex.tLocalPoint = (*I).tLocalPoint; tVertex.tGlobalPoint = (*I).tGlobalPoint; tVertex.tNodeID = (*I).tNodeID; Memory.mem_copy (tVertex.tVertexTypes,(*I).tVertexTypes,GameGraph::LOCATION_TYPE_COUNT*sizeof(GameGraph::_LOCATION_ID)); tVertex.tLevelID = (*I).tLevelID; tVertex.dwEdgeOffset = dwOffset; tVertex.dwPointOffset = dwPointOffset; VERIFY ((*I).tNeighbourCount < (u32(1) << (8*sizeof(u8)))); tVertex.tNeighbourCount = (u8)(*I).tNeighbourCount; VERIFY ((*I).tDeathPointCount < (u32(1) << (8*sizeof(u8)))); tVertex.tDeathPointCount= (u8)(*I).tDeathPointCount; tMemoryStream.w (&tVertex,sizeof(tVertex)); dwOffset += (*I).tNeighbourCount*sizeof(CGameGraph::CEdge); dwPointOffset += (*I).tDeathPointCount*sizeof(CGameGraph::CLevelPoint); } };
void vfSaveEdges(CMemoryWriter &tMemoryStream) { GRAPH_VERTEX_IT I = m_tpVertices.begin(); GRAPH_VERTEX_IT E = m_tpVertices.end(); for ( ; I != E; I++) for (int i=0; i<(int)(*I).tNeighbourCount; i++) tMemoryStream.w ((*I).tpaEdges + i,sizeof(CGameGraph::CEdge)); };
IC void write_file_header (LPCSTR file_name, const u32 &crc, const u32 &ptr, const u32 &size_real, const u32 &size_compressed) { #ifndef PROTECTED_BUILD fs_desc.w_stringZ (file_name); fs_desc.w_u32 (crc); // crc fs_desc.w_u32 (ptr); fs_desc.w_u32 (size_real); fs_desc.w_u32 (size_compressed); #else // PROTECTED_BUILD u32 file_name_size = (xr_strlen(file_name) + 0)*sizeof(char); u32 buffer_size = file_name_size + 4*sizeof(u32); VERIFY (buffer_size <= 65535); u32 full_buffer_size = buffer_size + sizeof(u16); u8 *buffer = (u8*)_alloca(full_buffer_size); u8 *buffer_start = buffer; *(u16*)buffer = (u16)buffer_size; buffer += sizeof(u16); *(u32*)buffer = size_real; buffer += sizeof(u32); *(u32*)buffer = size_compressed; buffer += sizeof(u32); *(u32*)buffer = crc; buffer += sizeof(u32); Memory.mem_copy (buffer,file_name,file_name_size); buffer += file_name_size; *(u32*)buffer = ptr; // trivial_encryptor::encode (buffer_start,full_buffer_size,buffer_start); fs_desc.w (buffer_start,full_buffer_size); #endif // PROTECTED_BUILD }
CLevelGameGraph ( LPCSTR graph_file_name, LPCSTR raw_cross_table_file_name, CGameGraph::SLevel *tLevel, LPCSTR S, u32 dwOffset, u32 dwLevelID, CInifile *Ini ) { m_tLevel = *tLevel; m_dwOffset = dwOffset; m_tpLevelPoints.clear (); FILE_NAME caFileName; // loading graph strcpy_s (caFileName,graph_file_name); m_tpGraph = new CGameGraph(caFileName); strcpy_s (caFileName,raw_cross_table_file_name); CGameLevelCrossTable *l_tpCrossTable = new CGameLevelCrossTable(caFileName); CLevelGraph *l_tpAI_Map = new CLevelGraph(S); VERIFY2 (l_tpCrossTable->header().level_guid() == l_tpAI_Map->header().guid(), "cross table doesn't correspond to the AI-map, rebuild graph!"); VERIFY2 (l_tpCrossTable->header().game_guid() == m_tpGraph->header().guid(), "cross table doesn't correspond to the graph, rebuild graph!"); VERIFY2 (m_tpGraph->header().level(GameGraph::_LEVEL_ID(0)).guid() == l_tpAI_Map->header().guid(), "cross table doesn't correspond to the AI-map, rebuild graph!"); VERIFY (l_tpAI_Map->header().vertex_count() == l_tpCrossTable->header().level_vertex_count()); VERIFY (m_tpGraph->header().vertex_count() == l_tpCrossTable->header().game_vertex_count()); tLevel->m_guid = l_tpAI_Map->header().guid(); { for (GameGraph::_GRAPH_ID i=0, n = m_tpGraph->header().vertex_count(); i<n; ++i) if ((!l_tpAI_Map->valid_vertex_id(m_tpGraph->vertex(i)->level_vertex_id()) || (l_tpCrossTable->vertex(m_tpGraph->vertex(i)->level_vertex_id()).game_vertex_id() != i) || !l_tpAI_Map->inside(m_tpGraph->vertex(i)->level_vertex_id(),m_tpGraph->vertex(i)->level_point()))) { Msg ("! Graph doesn't correspond to the cross table"); R_ASSERT2 (false,"Graph doesn't correspond to the cross table"); } } m_tpVertices.resize (m_tpGraph->header().vertex_count()); GRAPH_VERTEX_IT B = m_tpVertices.begin(); GRAPH_VERTEX_IT I = B; GRAPH_VERTEX_IT E = m_tpVertices.end(); for ( ; I != E; I++) { (*I).tLocalPoint = m_tpGraph->vertex(int(I - B))->level_point(); (*I).tGlobalPoint.add (m_tpGraph->vertex(int(I - B))->game_point(),m_tLevel.offset()); (*I).tLevelID = dwLevelID; (*I).tNodeID = m_tpGraph->vertex(int(I - B))->level_vertex_id(); Memory.mem_copy ((*I).tVertexTypes,m_tpGraph->vertex(int(I - B))->vertex_type(),GameGraph::LOCATION_TYPE_COUNT*sizeof(GameGraph::_LOCATION_ID)); (*I).tNeighbourCount = m_tpGraph->vertex(int(I - B))->edge_count(); CGameGraph::const_iterator b,i,e; m_tpGraph->begin (int(I - B),i,e); (*I).tpaEdges = (CGameGraph::CEdge*)xr_malloc((*I).tNeighbourCount*sizeof(CGameGraph::CEdge)); b = i; for ( ; i != e; ++i) { GameGraph::CEdge &edge = (*I).tpaEdges[i - b]; edge = *i; VERIFY ((edge.vertex_id() + dwOffset) < (u32(1) << (8*sizeof(GameGraph::_GRAPH_ID)))); edge.m_vertex_id = (GameGraph::_GRAPH_ID)(edge.m_vertex_id + dwOffset); } (*I).dwPointOffset = 0; vfGenerateDeathPoints (int(I - B),l_tpCrossTable,l_tpAI_Map,(*I).tDeathPointCount); } xr_delete (l_tpCrossTable); xr_delete (l_tpAI_Map); // updating cross-table { strcpy_s (caFileName,raw_cross_table_file_name); CGameLevelCrossTable *tpCrossTable = new CGameLevelCrossTable(caFileName); xr_vector<CGameLevelCrossTable::CCell> tCrossTableUpdate; tCrossTableUpdate.resize(tpCrossTable->header().level_vertex_count()); for (int i=0; i<(int)tpCrossTable->header().level_vertex_count(); i++) { tCrossTableUpdate[i] = tpCrossTable->vertex(i); VERIFY (u32(tCrossTableUpdate[i].tGraphIndex) < tpCrossTable->header().game_vertex_count()); tCrossTableUpdate[i].tGraphIndex = tCrossTableUpdate[i].tGraphIndex + (GameGraph::_GRAPH_ID)dwOffset; } CGameLevelCrossTable::CHeader tCrossTableHeader; tCrossTableHeader.dwVersion = XRAI_CURRENT_VERSION; tCrossTableHeader.dwNodeCount = tpCrossTable->m_tCrossTableHeader.dwNodeCount; tCrossTableHeader.dwGraphPointCount = tpCrossTable->m_tCrossTableHeader.dwGraphPointCount; tCrossTableHeader.m_level_guid = tpCrossTable->m_tCrossTableHeader.m_level_guid; tCrossTableHeader.m_game_guid = tGraphHeader.m_guid; xr_delete (tpCrossTable); m_cross_table.w(&tCrossTableHeader,sizeof(tCrossTableHeader)); for (int i=0; i<(int)tCrossTableHeader.dwNodeCount; i++) m_cross_table.w(&(tCrossTableUpdate[i]),sizeof(tCrossTableUpdate[i])); } // fill vertex map { string_path fName; strconcat (sizeof(fName),fName,S,"level.spawn"); IReader *F = FS.r_open(fName); u32 id; IReader *O = F->open_chunk_iterator(id); for (int i=0; O; O = F->open_chunk_iterator(id,O)) { NET_Packet P; P.B.count = O->length(); O->r (P.B.data,P.B.count); u16 ID; P.r_begin (ID); R_ASSERT (M_SPAWN==ID); P.r_stringZ (fName); CSE_Abstract *E = F_entity_Create(fName); R_ASSERT3 (E,"Can't create entity.",fName); // E->Spawn_Read (P); CSE_ALifeGraphPoint *tpGraphPoint = smart_cast<CSE_ALifeGraphPoint*>(E); if (tpGraphPoint) { E->Spawn_Read (P); Fvector tVector; tVector = tpGraphPoint->o_Position; GameGraph::_GRAPH_ID tGraphID = GameGraph::_GRAPH_ID(-1); float fMinDistance = 1000000.f; { GRAPH_VERTEX_IT B = m_tpVertices.begin(); GRAPH_VERTEX_IT I = B; GRAPH_VERTEX_IT E = m_tpVertices.end(); for ( ; I != E; I++) { float fDistance = (*I).tLocalPoint.distance_to(tVector); if (fDistance < fMinDistance) { fMinDistance = fDistance; tGraphID = GameGraph::_GRAPH_ID(I - B); if (fMinDistance < EPS_L) break; } } } if (fMinDistance < EPS_L) { SConnectionVertex T; LPSTR S; S = xr_strdup(tpGraphPoint->name_replace()); T.caConnectName = xr_strdup(*tpGraphPoint->m_caConnectionPointName); T.dwLevelID = dwfGetIDByLevelName(Ini,*tpGraphPoint->m_caConnectionLevelName); // T.tGraphID = (GameGraph::_GRAPH_ID)i; // T.tOldGraphID = tGraphID; T.tOldGraphID = (GameGraph::_GRAPH_ID)i; T.tGraphID = tGraphID; bool ok = true; VERTEX_MAP::const_iterator II = m_tVertexMap.begin(); VERTEX_MAP::const_iterator EE = m_tVertexMap.end(); for ( ; II != EE; ++II) if (T.tOldGraphID == (*II).second.tOldGraphID) { ok = false; Msg ("Graph point %s is removed,because it has the same position as some another graph point",E->name_replace()); break; } if (ok) { m_tVertexMap.insert (mk_pair(S,T)); i++; } } } F_entity_Destroy (E); } if (i != m_tpGraph->header().vertex_count()) Msg ("Graph for the level %s doesn't correspond to the graph points from Level Editor! (%d : %d)",*m_tLevel.name(),i,m_tpGraph->header().vertex_count()); VERTEX_MAP::const_iterator I = m_tVertexMap.begin(); VERTEX_MAP::const_iterator E = m_tVertexMap.end(); for ( ; I != E; ++I) { R_ASSERT3 (!xr_strlen((*I).second.caConnectName) || ((*I).second.tGraphID < m_tpVertices.size()),"Rebuild graph for the level",*m_tLevel.name()); } // VERIFY3 (i == m_tpGraph->header().vertex_count(), "Rebuild graph for the level ",m_tLevel.name()); O->close (); FS.r_close (F); } };
bool EDetailManager::Export(LPCSTR path) { AnsiString fn = AnsiString(path)+"build.details"; bool bRes=true; SPBItem* pb = UI->ProgressStart(5,"Making details..."); CMemoryWriter F; pb->Inc ("merge textures"); Fvector2Vec offsets; Fvector2Vec scales; boolVec rotated; RStringSet textures_set; RStringVec textures; U32Vec remap; U8Vec remap_object (objects.size(),u8(-1)); int slot_cnt = dtH.size_x*dtH.size_z; for (int slot_idx=0; slot_idx<slot_cnt; slot_idx++){ DetailSlot* it = &dtSlots[slot_idx]; for (int part=0; part<4; part++){ u8 id = it->r_id(part); if (id!=DetailSlot::ID_Empty) { textures_set.insert(((EDetail*)(objects[id]))->GetTextureName()); remap_object[id] = 1; } } } textures.assign (textures_set.begin(),textures_set.end()); U8It remap_object_it= remap_object.begin(); u32 new_idx = 0; for (DetailIt d_it=objects.begin(); d_it!=objects.end(); d_it++,remap_object_it++) if ((*remap_object_it==1)&&(textures_set.find(((EDetail*)(*d_it))->GetTextureName())!=textures_set.end())) *remap_object_it = (u8)new_idx++; AnsiString do_tex_name = ChangeFileExt(fn,"_details"); int res = ImageLib.CreateMergedTexture(textures,do_tex_name.c_str(),STextureParams::tfADXT1,256,1024,256,1024,offsets,scales,rotated,remap); if (1!=res) bRes=FALSE; pb->Inc ("export geometry"); // objects int object_idx = 0; if (bRes){ do_tex_name = ExtractFileName(do_tex_name); F.open_chunk (DETMGR_CHUNK_OBJECTS); for (DetailIt it=objects.begin(); it!=objects.end(); it++){ if (remap_object[it-objects.begin()]!=u8(-1)){ F.open_chunk (object_idx++); if (!((EDetail*)(*it))->m_pRefs){ ELog.DlgMsg(mtError, "Bad object or object not found '%s'.", ((EDetail*)(*it))->m_sRefs.c_str()); bRes=false; }else{ LPCSTR tex_name = ((EDetail*)(*it))->GetTextureName(); for (u32 t_idx=0; t_idx<textures.size(); t_idx++) if (textures[t_idx]==tex_name) break; VERIFY(t_idx<textures.size()); t_idx = remap[t_idx]; ((EDetail*)(*it))->Export (F,do_tex_name.c_str(),offsets[t_idx],scales[t_idx],rotated[t_idx]); } F.close_chunk (); if (!bRes) break; } } F.close_chunk (); } pb->Inc ("export slots"); // slots if (bRes){ xr_vector<DetailSlot> dt_slots(slot_cnt); dt_slots.assign(dtSlots,dtSlots+slot_cnt); for (slot_idx=0; slot_idx<slot_cnt; slot_idx++){ DetailSlot& it = dt_slots[slot_idx]; // zero colors need lighting it.c_dir = 0; it.c_hemi = 0; it.c_r = 0; it.c_g = 0; it.c_b = 0; for (int part=0; part<4; part++){ u8 id = it.r_id(part); if (id!=DetailSlot::ID_Empty) it.w_id(part,remap_object[id]); } } F.open_chunk (DETMGR_CHUNK_SLOTS); F.w (dt_slots.begin(),dtH.size_x*dtH.size_z*sizeof(DetailSlot)); F.close_chunk (); pb->Inc(); // write header dtH.version = DETAIL_VERSION; dtH.object_count= object_idx; F.w_chunk (DETMGR_CHUNK_HEADER,&dtH,sizeof(DetailHeader)); bRes = F.save_to(fn.c_str()); } pb->Inc(); UI->ProgressEnd(pb); return bRes; }
void CGameGraphBuilder::save_graph (const float &start, const float &amount) { Progress (start); Msg ("Saving graph"); // header CMemoryWriter writer; CGameGraph::CHeader header; header.m_version = XRAI_CURRENT_VERSION; VERIFY (graph().vertices().size() < (u32(1) << (8*sizeof(GameGraph::_GRAPH_ID)))); header.m_vertex_count = (GameGraph::_GRAPH_ID)graph().vertices().size(); VERIFY (graph().edge_count() < (u32(1) << (8*sizeof(GameGraph::_GRAPH_ID)))); header.m_edge_count = (GameGraph::_GRAPH_ID)graph().edge_count(); header.m_death_point_count = 0; header.m_guid = m_graph_guid; // levels CGameGraph::SLevel level; level.m_offset.set (0,0,0); level.m_id = 0; level.m_name = m_level_name; level.m_section = ""; level.m_guid = level_graph().header().guid(); header.m_levels.insert (std::make_pair(level.m_id,level)); header.save (&writer); { u32 edge_offset = graph().vertices().size()*sizeof(CGameGraph::CVertex); graph_type::const_vertex_iterator I = graph().vertices().begin(); graph_type::const_vertex_iterator E = graph().vertices().end(); for ( ; I != E; ++I) { CGameGraph::CVertex &vertex = (*I).second->data(); VERIFY ((*I).second->edges().size() < 256); vertex.tNeighbourCount = (u8)(*I).second->edges().size(); vertex.dwEdgeOffset = edge_offset; edge_offset += vertex.tNeighbourCount*sizeof(CGameGraph::CEdge); writer.w (&vertex,sizeof(CGameGraph::CVertex)); } } { graph_type::const_vertex_iterator I = graph().vertices().begin(); graph_type::const_vertex_iterator E = graph().vertices().end(); for ( ; I != E; ++I) { graph_type::const_iterator i = (*I).second->edges().begin(); graph_type::const_iterator e = (*I).second->edges().end(); for ( ; i != e; ++i) { GameGraph::CEdge edge; VERIFY ((*i).vertex_id() < (u32(1) << (8*sizeof(GameGraph::_GRAPH_ID)))); edge.m_vertex_id = (GameGraph::_GRAPH_ID)(*i).vertex_id(); edge.m_path_distance = (*i).weight(); writer.w (&edge.m_vertex_id,sizeof(edge.m_vertex_id)); writer.w_float (edge.m_path_distance); } } } #ifdef PRIQUEL writer.save_to (m_graph_name); #else // PRIQUEL string_path file_name; strconcat (sizeof(file_name),file_name,*m_level_name,GAME_LEVEL_GRAPH); writer.save_to (file_name); #endif // PRIQUEL Msg ("%d bytes saved",int(writer.size())); Progress (start + amount); }
CCrossTableBuilder::CCrossTableBuilder(LPCSTR caProjectName) { FILE_NAME caFileName; strconcat (sizeof(caFileName),caFileName,caProjectName,GAME_LEVEL_GRAPH); Phase ("Loading level graph"); CGameGraph tGraph(caFileName); Phase ("Loading AI map"); CLevelGraph tMap(caProjectName); Phase ("Building dynamic objects"); FLOAT_VECTOR_VECTOR tDistances; int iVertexCount = tGraph.header().vertex_count(); R_ASSERT2 (iVertexCount > 0,"There are no graph points in the graph!"); int iNodeCount = tMap.header().vertex_count(); xr_vector<bool> tMarks; tMarks.assign (tMap.header().vertex_count(),false); { for (int i=0; i<iVertexCount; i++) vfRecurseMark(tMap,tMarks,tGraph.vertex(i)->level_vertex_id()); tMarks.flip (); } tDistances.resize (iVertexCount); { FLOAT_VECTOR_IT I = tDistances.begin(); FLOAT_VECTOR_IT E = tDistances.end(); for ( ; I != E; I++) { (*I).resize (iNodeCount); FLOAT_IT i = (*I).begin(); FLOAT_IT e = (*I).end(); for ( ; i != e; i++) *i = u32(-1); } } Phase ("Building cross table"); Progress(0.f); for (int i=0; i<iVertexCount; ++i) { if (i) for (int k=0; k<(int)tMap.header().vertex_count(); k++) tDistances[i][k] = tDistances[i - 1][k]; g_tDistances = &tDistances[i]; g_tMap = &tMap; g_tMarks = &tMarks; vfRecurseUpdate(tGraph.vertex(i)->level_vertex_id(),i,iVertexCount); Progress(float(i + 1)/float(iVertexCount)); } Progress (1.f); Phase ("Saving cross table"); CMemoryWriter tMemoryStream; CGameLevelCrossTable::CHeader tCrossTableHeader; tCrossTableHeader.dwVersion = XRAI_CURRENT_VERSION; tCrossTableHeader.dwNodeCount = iNodeCount; tCrossTableHeader.dwGraphPointCount = iVertexCount; tCrossTableHeader.m_level_guid = tMap.header().guid(); tCrossTableHeader.m_game_guid = tGraph.header().guid(); tMemoryStream.open_chunk (CROSS_TABLE_CHUNK_VERSION); tMemoryStream.w (&tCrossTableHeader,sizeof(tCrossTableHeader)); tMemoryStream.close_chunk (); tMemoryStream.open_chunk (CROSS_TABLE_CHUNK_DATA); { for (int i=0; i<iNodeCount; i++) { FLOAT_VECTOR_IT I = tDistances.begin(), B = I; FLOAT_VECTOR_IT E = tDistances.end(); CGameLevelCrossTable::CCell tCrossTableCell; tCrossTableCell.fDistance = flt_max; tCrossTableCell.tGraphIndex = u16(-1); for ( ; I != E; I++) if (float((*I)[i])*tMap.header().cell_size() < tCrossTableCell.fDistance) { tCrossTableCell.fDistance = float((*I)[i])*tMap.header().cell_size(); tCrossTableCell.tGraphIndex = GameGraph::_GRAPH_ID(I - B); } for (int j=0; j<iVertexCount; j++) if ((tGraph.vertex(j)->level_vertex_id() == (u32)i) && (tCrossTableCell.tGraphIndex != j)) { Msg("! Warning : graph points are too close, therefore cross table is automatically validated"); Msg("%d : [%f][%f][%f] %d[%f] -> %d[%f]",i,VPUSH(tGraph.vertex(j)->level_point()),tCrossTableCell.tGraphIndex,tCrossTableCell.fDistance,j,tDistances[j][i]); tCrossTableCell.fDistance = float(tDistances[j][i])*tMap.header().cell_size(); tCrossTableCell.tGraphIndex = (GameGraph::_GRAPH_ID)j; } tMemoryStream.w(&tCrossTableCell,sizeof(tCrossTableCell)); } } tMemoryStream.close_chunk(); strconcat (sizeof(caFileName),caFileName,caProjectName,CROSS_TABLE_NAME_RAW); tMemoryStream.save_to(caFileName); }