Files
2026-06-01 12:46:52 +02:00

283 lines
9.3 KiB
C++

#include <windows.h>
#include "MapUtil.h"
#include "MapDefine.h"
#include "TerrainSeamlessWorldInfo.h"
namespace
{
const char* c_szMapFileExt = ".nfm";
const char* c_szScriptFileExt = ".nfs";
const char* c_szLocationFileExt = ".nfc";
const char* c_szAttributePolygonFileExt = ".nfa";
const char* c_szMinimapFileExt = ".bmp";
const char* c_szLQWaterFileExt = ".nfw";
const char* c_szPropFileExt = ".qpf";
const char* c_szEventAreaPolygonFileExt = ".nfe";
};
std::string CTerrainSeamlessWorldInfo::GetMapFileName( int nMapPosX, int nMapPosY ) const
{ return GetFileNameWithExt( nMapPosX, nMapPosY, c_szMapFileExt ); }
std::string CTerrainSeamlessWorldInfo::GetScriptFileName( int nMapPosX, int nMapPosY ) const
{ return GetFileNameWithExt( nMapPosX, nMapPosY, c_szScriptFileExt ); }
std::string CTerrainSeamlessWorldInfo::GetLocationFileName( int nMapPosX, int nMapPosY ) const
{ return GetFileNameWithExt( nMapPosX, nMapPosY, c_szLocationFileExt ); }
std::string CTerrainSeamlessWorldInfo::GetAttributePolygonFileName( int nMapPosX, int nMapPosY ) const
{ return GetFileNameWithExt( nMapPosX, nMapPosY, c_szAttributePolygonFileExt ); }
std::string CTerrainSeamlessWorldInfo::GetFieldPropFileName( int nMapPosX, int nMapPosY ) const
{ return GetFileNameWithExt( nMapPosX, nMapPosY, c_szPropFileExt ); }
std::string CTerrainSeamlessWorldInfo::GetMinimapImageFileName( int nMapPosX, int nMapPosY ) const
{ return GetFileNameWithExt( nMapPosX, nMapPosY, c_szMinimapFileExt ); }
std::string CTerrainSeamlessWorldInfo::GetLQWaterFileName( int nMapPosX, int nMapPosY ) const
{ return GetFileNameWithExt( nMapPosX, nMapPosY, c_szLQWaterFileExt ); }
std::string CTerrainSeamlessWorldInfo::GetEventAreaFileName( int nMapPosX, int nMapPosY ) const
{ return GetFileNameWithExt( nMapPosX, nMapPosY, c_szEventAreaPolygonFileExt ); }
int CTerrainSeamlessWorldInfo::GetWorldID( int nMapPosX, int nMapPosY ) const
{
if( 0 <= nMapPosX && nMapPosX < m_sizMapCount.cx && 0 <= nMapPosY && nMapPosY < m_sizMapCount.cy )
{
FILENAMEMAP::const_iterator it = m_FileNameMap.find( (nMapPosY * m_sizMapCount.cx) + nMapPosX );
if( it != m_FileNameMap.end() )
return it->second.m_nWorldID;
}
return -1;
}
CTerrainSeamlessWorldInfo::CTerrainSeamlessWorldInfo()
: m_nTileCountPerSegment( 0 )
, m_nSegmentCountPerMap( 0 )
, m_fTileLength( 0.f )
, m_sizMapCount( KSize( 0, 0 ) )
, m_fFOV( 0.f )
, m_nMapLayer( 0 )
{
}
CTerrainSeamlessWorldInfo::~CTerrainSeamlessWorldInfo()
{
Release();
}
bool CTerrainSeamlessWorldInfo::Initialize( const char* szSeamlessWorldInfoFileName, bool bMapFileCheck/* = true*/ )
{
Release();
// 파일로부터 text들을 읽어낸다.
STRING_VECTOR TextLines;
{
KStream* pStream = GetResourceStream( szSeamlessWorldInfoFileName );
if( NULL == pStream ) return false;
int nTextLength = int( pStream->GetLength() );
char* pEntireText = new char[ nTextLength + 1 ];
pStream->Read( pEntireText, sizeof(char) * nTextLength );
pEntireText[ nTextLength ] = '\0';
delete pStream;
CStringUtil::GetTextLinesFromString( pEntireText, TextLines );
delete [] pEntireText;
}
const char* c_szTileLength = "TILE_LENGTH=";
const char* c_szTileCountPerSegment = "TILECOUNT_PER_SEGMENT=";
const char* c_szSegmentCountPerMap = "SEGMENTCOUNT_PER_MAP=";
const char* c_szMapSize = "MAPSIZE=";
const char* c_szMapFIle = "MAPFILE=";
const char* c_szFOV = "SETFOV=";
const char* c_szMapLayer = "MAPLAYER=";
float fTileLength = 0.f;
int nTileCountPerSegment = 0;
int nSegmentCountPerMap = 0;
int nMapCountX = 0;
int nMapCountY = 0;
float fFOV = 0.f;
int nMapLayer = 0;
for( size_t n = 0; n < TextLines.size(); ++n )
{
std::string strLine = TextLines[n];
if( ';' == strLine[0] ) continue;
std::string strContent;
// tile length
if( CStringUtil::GetContentString( strLine, c_szTileLength, strContent ) )
fTileLength = float( ::atof( strContent.c_str() ) );
// tile count per segment
else if( CStringUtil::GetContentString( strLine, c_szTileCountPerSegment, strContent ) )
nTileCountPerSegment = ::atoi( strContent.c_str() );
// segment count per map
else if( CStringUtil::GetContentString( strLine, c_szSegmentCountPerMap, strContent ) )
nSegmentCountPerMap = ::atoi( strContent.c_str() );
else if( CStringUtil::GetContentString( strLine, c_szFOV, strContent ) )
fFOV = float( ::atof( strContent.c_str() ) );
else if( CStringUtil::GetContentString( strLine, c_szMapLayer, strContent ) )
nMapLayer = ::atoi( strContent.c_str() );
// map size
else if( CStringUtil::GetContentString( strLine, c_szMapSize, strContent ) )
{
if( 0 != nMapCountX || 0 != nMapCountY ) return false; // map size항목이 2번 이상 나온 경우
// ',' 문자를 찾는다.
std::string::size_type CommaPos = strContent.find( ',' );
if( CommaPos == std::string::npos ) return false;
// ',' 앞의 가로 갯수
std::string strMapCountX;
strMapCountX.assign( strContent, 0, CommaPos );
// ',' 뒤의 세로 갯수
std::string strMapCountY;
strMapCountY.assign( strContent, CommaPos + 1, strContent.size() - (CommaPos + 1) );
if( strMapCountX.empty() || strMapCountY.empty() ) return false;
nMapCountX = ::atoi( strMapCountX.c_str() );
nMapCountY = ::atoi( strMapCountY.c_str() );
if( nMapCountX <= 0 || nMapCountY <= 0 ) return false;
}
// map file
else if( CStringUtil::GetContentString( strLine, c_szMapFIle, strContent ) )
{
if( 0 == nMapCountX && 0 == nMapCountY ) return false; // map size항목이 아직 안나온 경우
// ',' 문자를 2번 찾는다.
std::string::size_type CommaPos1 = strContent.find( ',' );
if( CommaPos1 == std::string::npos ) return false;
std::string::size_type CommaPos2 = strContent.find( ',', (CommaPos1 + 1) );
if( CommaPos2 == std::string::npos ) return false;
std::string::size_type CommaPos3 = strContent.find( ',', (CommaPos2 + 1) );
if( CommaPos3 == std::string::npos ) return false;
std::string::size_type CommaPos4 = strContent.find( ',', (CommaPos3 + 1) );
if( CommaPos4 == std::string::npos ) return false;
// 첫번째 ',' 앞의 맵 x위치
std::string strMapX;
strMapX.assign( strContent, 0, CommaPos1 );
// 두번째 ',' 앞의 맵 y위치
std::string strMapY;
strMapY.assign( strContent, (CommaPos1 + 1), CommaPos2 - (CommaPos1 + 1) );
// 세번째 ',' 앞의 맵 layer위치
std::string strMapLayer;
strMapLayer.assign( strContent, (CommaPos2 + 1), CommaPos3 - (CommaPos2 + 1) );
// 세번째 ',' 뒤의 맵 파일명
std::string strMapFileName;
strMapFileName.assign( strContent, (CommaPos3 + 1), CommaPos4 - (CommaPos3 + 1) );
std::string strWorldMap;
strWorldMap.assign( strContent, (CommaPos4 + 1 ), strContent.size() - (CommaPos4 + 1) );
if( strMapX.empty() || strMapY.empty() || strMapLayer.empty() || strMapFileName.empty() ) return false;
int nMapX = ::atoi( strMapX.c_str() );
int nMapY = ::atoi( strMapY.c_str() );
int nMapLay = ::atoi( strMapLayer.c_str() );
if( nMapX < 0 || nMapX >= nMapCountX ) return false;
if( nMapY < 0 || nMapY >= nMapCountY ) return false;
if( nMapLay < 0 ) return false;
int nWorldMapID = ::atoi( strWorldMap.c_str() );
int nMapIndex = (nMapY * nMapCountX) + nMapX + nMapLay;
// 같은 위치에 map file항목이 2번 이상 나온 경우
if( m_FileNameMap.find( nMapIndex ) != m_FileNameMap.end() ) return false;
FILENAME_MAPINFO mapinfo;
mapinfo.m_strMapFileName = strMapFileName;
mapinfo.m_nWorldID = nWorldMapID;
m_FileNameMap.insert( std::make_pair( nMapIndex, mapinfo ) );
}
}
// 파라미터가 정상인지 확인
if( fTileLength <= 0.f || nTileCountPerSegment <= 0 || nSegmentCountPerMap <= 0 ) return false;
// 한개 이상의 맵이 로드 되었는지 확인
if( m_FileNameMap.empty() ) return false;
m_nTileCountPerSegment = nTileCountPerSegment;
m_nSegmentCountPerMap = nSegmentCountPerMap;
m_fTileLength = fTileLength;
m_nMapLayer = nMapLayer;
m_sizMapCount.cx = nMapCountX;
m_sizMapCount.cy = nMapCountY;
if( 0.f < fFOV ) m_fFOV = fFOV;
// 모든 맵 파일이 정상인지 확인
if( bMapFileCheck )
{
for( int nY( 0 ); nY < nMapCountY; ++nY )
{
for( int nX( 0 ); nX < nMapCountX; ++nX )
{
std::string strMapFileName = GetMapFileName( nX, nY );
if( !strMapFileName.empty() )
{
// 맵 파일 열기
KStream* pStream = GetResourceStream( strMapFileName.c_str() );
if( NULL == pStream ) return false;
// 헤더 읽기
NFM_LATESTHEADER header;
if( sizeof(header) != pStream->Read( &header, sizeof(header) ) )
{
delete pStream;
return false;
}
delete pStream;
// 식별 문자열 검사
std::string strSign = header.szSign;
if( strSign.compare( NFMFILE_SIGN ) != 0 ) return false;
// 버전 체크
if( header.dwVersion != c_dwNFMCurrentVer ) return false;
// 파라미터가 동일한지 체크
if( header.nTileCountPerSegment != nTileCountPerSegment ||
header.nSegmentCountPerMap != nSegmentCountPerMap ||
header.fTileLength != fTileLength ) return false;
}
}
}
}
return true;
}
void CTerrainSeamlessWorldInfo::Release()
{
m_nTileCountPerSegment = 0;
m_nSegmentCountPerMap = 0;
m_fTileLength = 0.f;
m_sizMapCount = KSize( 0, 0 );
m_FileNameMap.clear();
m_nMapLayer = 0;
}