khanat-opennel-code/code/ryzom/tools/client/client_data_check/client_data_check.cpp

435 lines
11 KiB
C++

// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// client_data_check.cpp : Defines the class behaviors for the application.
//
#include "nel/misc/time_nl.h"
#include "nel/misc/ucstring.h"
#include "nel/misc/algo.h"
#include "data_scan.h"
#include "nel/misc/debug.h"
#include "nel/misc/big_file.h"
#include "nel/misc/file.h"
#include "3d/shape.h"
#include "3d/mesh_mrm.h"
#include "3d/mesh_mrm_skinned.h"
#include "3d/register_3d.h"
#include "stdafx.h"
#include "client_data_check.h"
#include "client_data_checkDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#pragma optimize("",off)
/////////////////////////////////////////////////////////////////////////////
// CClient_data_checkApp
BEGIN_MESSAGE_MAP(CClient_data_checkApp, CWinApp)
//{{AFX_MSG_MAP(CClient_data_checkApp)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG
ON_COMMAND(ID_HELP, CWinApp::OnHelp)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CClient_data_checkApp construction
CClient_data_checkApp::CClient_data_checkApp()
{
_CheckDlg= NULL;
_StateProcess= Init;
_BnpIndex= 0;
_FileIndex= 0;
}
/////////////////////////////////////////////////////////////////////////////
// The one and only CClient_data_checkApp object
CClient_data_checkApp theApp;
/////////////////////////////////////////////////////////////////////////////
// CClient_data_checkApp initialization
BOOL CClient_data_checkApp::InitInstance()
{
AfxEnableControlContainer();
// Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need.
#ifdef _AFXDLL
Enable3dControls(); // Call this when using MFC in a shared DLL
#else
Enable3dControlsStatic(); // Call this when linking to MFC statically
#endif
// init path
NLMISC::CPath::addSearchPath("data");
NLMISC::CPath::addSearchPath("unpack");
NL3D::registerSerial3d();
// init debug
NLMISC::createDebug();
NLMISC::CFileDisplayer *DataCheckLogDisplayer= new NLMISC::CFileDisplayer("data_check.log", true, "DATA_CHECK.LOG");
NLMISC::DebugLog->addDisplayer (DataCheckLogDisplayer);
NLMISC::InfoLog->addDisplayer (DataCheckLogDisplayer);
NLMISC::WarningLog->addDisplayer (DataCheckLogDisplayer);
NLMISC::ErrorLog->addDisplayer (DataCheckLogDisplayer);
NLMISC::AssertLog->addDisplayer (DataCheckLogDisplayer);
// init dlg
_CheckDlg= new CClient_data_checkDlg(this);
_CheckDlg->Create(CClient_data_checkDlg::IDD);
m_pMainWnd = _CheckDlg;
/*int nResponse = dlg.DoModal();
if (nResponse == IDOK)
{
// TODO: Place code here to handle when the dialog is
// dismissed with OK
}
else if (nResponse == IDCANCEL)
{
// TODO: Place code here to handle when the dialog is
// dismissed with Cancel
}*/
return TRUE;
}
// ***************************************************************************
void CClient_data_checkApp::setLog()
{
if(_CheckDlg)
{
_CheckDlg->ListBox.ResetContent();
std::string tam= _LastDataScanLog.toString();
std::vector<std::string> listStr;
NLMISC::splitString(tam, "\n", listStr);
for(uint i=0;i<listStr.size();i++)
_CheckDlg->ListBox.AddString(listStr[i].c_str());
_CheckDlg->UpdateData(FALSE);
}
}
// ***************************************************************************
void CClient_data_checkApp::addLog(const std::string &logAdd)
{
_LastDataScanLog+= std::string("\n") + logAdd;
setLog();
}
// ***************************************************************************
void CClient_data_checkApp::setStatus(const std::string &status)
{
if(_CheckDlg)
{
_CheckDlg->TextStatus= status.c_str();
_CheckDlg->UpdateData(FALSE);
}
}
// ***************************************************************************
void CClient_data_checkApp::checkMeshMrm(const std::string &fileName, NL3D::CMeshMRM *meshMrm)
{
uint numLod= meshMrm->getNbLod();
uint numVerts= meshMrm->getMeshGeom().getVertexBuffer().getNumVertices();
if(numLod==0)
{
addLog(std::string("Warning: The File: ") + fileName + "has 0 Lods");
}
else
{
const NL3D::CMeshMRMGeom& meshGeom= meshMrm->getMeshGeom();
// Scan all Geomoprhs
for(uint i=0;i<numLod;i++)
{
const std::vector<NL3D::CMRMWedgeGeom> &geoms= meshGeom.getGeomorphs(i);
for(uint j=0;j<geoms.size();j++)
{
if(geoms[j].Start>=numVerts || geoms[j].End>=numVerts)
{
addLog(NLMISC::toString("ERROR: The Mrm File: %s has a bad Geomorph. Lod: %d. Vert: %d. Start/End: %d/%d. Max:%d",
fileName.c_str(), i, j, geoms[j].Start, geoms[j].End, numVerts));
}
}
}
}
}
// ***************************************************************************
void CClient_data_checkApp::checkMeshMrmSkinned(const std::string &fileName, NL3D::CMeshMRMSkinned *meshMrm)
{
uint numLod= meshMrm->getNbLod();
NL3D::CVertexBuffer vb;
meshMrm->getMeshGeom().getVertexBuffer(vb);
uint numVerts= vb.getNumVertices();
if(numLod==0)
{
addLog(std::string("Warning: The File: ") + fileName + "has 0 Lods");
}
else
{
const NL3D::CMeshMRMSkinnedGeom& meshGeom= meshMrm->getMeshGeom();
// Scan all Geomoprhs
for(uint i=0;i<numLod;i++)
{
const std::vector<NL3D::CMRMWedgeGeom> &geoms= meshGeom.getGeomorphs(i);
for(uint j=0;j<geoms.size();j++)
{
if(geoms[j].Start>=numVerts || geoms[j].End>=numVerts)
{
addLog(NLMISC::toString("ERROR: The MrmSkinned File: %s has a bad Geomorph. Lod: %d. Vert: %d. Start/End: %d/%d. Max:%d",
fileName.c_str(), i, j, geoms[j].Start, geoms[j].End, numVerts));
}
}
}
}
}
// ***************************************************************************
bool CClient_data_checkApp::processBnpMRM()
{
// init bnp list?
if(_BnpList.empty())
{
NLMISC::CPath::getPathContent("./data/", false, false, true, _BnpList);
if(_BnpList.empty())
{
std::string tam= "Don't find any BNP files for MRM Check";
_LastDataScanLog+= tam;
nlinfo(tam.c_str());
}
else
{
// add path into BNP
NLMISC::CPath::addSearchPath("data", true, false);
}
_BnpIndex= 0;
_FileIndex= 0;
}
// if some BNP to look through
if(_BnpIndex<_BnpList.size())
{
std::string bnpName= NLMISC::CFile::getFilename(_BnpList[_BnpIndex]);
// get the list of file in this bnp
if(_CurrentBnpFileList.empty())
{
// List all files From the bnp
if(NLMISC::CFile::getExtension(bnpName)=="bnp" || NLMISC::CFile::getExtension(bnpName)==".bnp")
NLMISC::CBigFile::getInstance().list(bnpName, _CurrentBnpFileList);
_FileIndex= 0;
}
// if some file to look throuh
if(_FileIndex<_CurrentBnpFileList.size())
{
std::string fileName= NLMISC::CFile::getFilename(_CurrentBnpFileList[_FileIndex]);
std::string status= NLMISC::toString("Checking File: BNP(%d/%d) - File(%d/%d)",
_BnpIndex, _BnpList.size(), _FileIndex, _CurrentBnpFileList.size());
if(NLMISC::CFile::getExtension(fileName)=="shape" || NLMISC::CFile::getExtension(fileName)==".shape")
{
// log
setStatus(status + "\nChecking Mesh File: " + fileName);
// try to load as mrm
std::string pathName= NLMISC::CPath::lookup(fileName);
NLMISC::CIFile file;
if(!pathName.empty() && file.open(pathName))
{
NL3D::CShapeStream ss;
ss.serial(file);
NL3D::CMeshMRM *meshMrm= dynamic_cast<NL3D::CMeshMRM*>(ss.getShapePointer());
NL3D::CMeshMRMSkinned *meshMrmSkinned= dynamic_cast<NL3D::CMeshMRMSkinned*>(ss.getShapePointer());
if(meshMrm)
checkMeshMrm(fileName, meshMrm);
if(meshMrmSkinned)
checkMeshMrmSkinned(fileName, meshMrmSkinned);
}
}
else
{
// log
setStatus(status);
}
// next file in this bnp
_FileIndex++;
}
else
{
// else next one
_BnpIndex++;
_CurrentBnpFileList.clear();
}
return false;
}
// else ended
else
return true;
}
// ***************************************************************************
BOOL CClient_data_checkApp::OnIdle(LONG lCount)
{
// Init
if(_StateProcess==Init)
{
CPatchManager::getInstance()->init();
CPatchManager::getInstance()->startScanDataThread();
_StateProcess=CheckSum;
}
// CheckSum pass?
if(_StateProcess==CheckSum || _StateProcess==CancelCheckSum)
{
CPatchManager *pPM= CPatchManager::getInstance();
// update messages
if(_StateProcess==CheckSum)
{
// get state
ucstring state;
std::vector<ucstring> stateLog;
if(pPM->getThreadState(state, stateLog))
{
setStatus(state.toString());
}
// get Log
ucstring dsLog;
if(pPM->getDataScanLog(dsLog))
{
_LastDataScanLog= dsLog;
setLog();
}
}
// if ended
bool res;
if(pPM->isScanDataThreadEnded(res))
{
// the log may have changed
ucstring dsLog;
if(pPM->getDataScanLog(dsLog))
{
_LastDataScanLog= dsLog;
setLog();
}
// Next
_StateProcess= MRMCheck;
}
}
// MRM Pass?
if(_StateProcess==MRMCheck )
{
if(processBnpMRM())
_StateProcess= NearEnd;
}
// Quit
if(_StateProcess==NearEnd )
{
// Report result
if(_LastDataScanLog.empty())
{
setStatus("Data Scan reported no corrupted Files.\nPress 'Close'");
nlinfo("Data Scan reported no corrupted Files.");
}
else
{
setStatus("Data Scan reported some corrupted Files.\nPlease send us the file 'data_check.log'.\nPress 'Close'");
nlinfo("");
nlinfo("");
nlinfo("*******************************************");
nlinfo("*******************************************");
nlinfo("Data Scan reported some corrupted Files.");
nlinfo("*******************************************");
nlinfo("*******************************************");
nlinfo("");
nlinfo("");
// Log
std::string tam= _LastDataScanLog.toString();
std::vector<std::string> listStr;
NLMISC::splitString(tam, "\n", listStr);
for(uint i=0;i<listStr.size();i++)
nlinfo("%s", listStr[i].c_str());
}
// Change Text
if(_CheckDlg)
{
_CheckDlg->CancelButton.SetWindowText("Close");
}
// End
_StateProcess= End;
}
return TRUE;
//return CWinApp::OnIdle(lCount);
}
// ***************************************************************************
void CClient_data_checkApp::cancel()
{
if(_StateProcess==CheckSum)
{
_StateProcess= CancelCheckSum;
CPatchManager::getInstance()->askForStopScanDataThread();
if(_CheckDlg)
{
_CheckDlg->TextStatus= "Canceling Data Scan. Please wait...";
_CheckDlg->UpdateData(FALSE);
}
}
if(_StateProcess==MRMCheck)
{
_StateProcess= NearEnd;
}
if(_StateProcess==End)
{
_CheckDlg->DestroyWindow();
delete _CheckDlg;
_CheckDlg= NULL;
// quit
exit(0);
}
}